Fix dcp::LocalTime constructor to cope with longer fractional second parts (DoM ...
[libdcp.git] / test / local_time_test.cc
1 /*
2     Copyright (C) 2014-2021 Carl Hetherington <cth@carlh.net>
3
4     This file is part of libdcp.
5
6     libdcp is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     libdcp is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with libdcp.  If not, see <http://www.gnu.org/licenses/>.
18
19     In addition, as a special exception, the copyright holders give
20     permission to link the code of portions of this program with the
21     OpenSSL library under certain conditions as described in each
22     individual source file, and distribute linked combinations
23     including the two.
24
25     You must obey the GNU General Public License in all respects
26     for all of the code used other than OpenSSL.  If you modify
27     file(s) with this exception, you may extend this exception to your
28     version of the file(s), but you are not obligated to do so.  If you
29     do not wish to do so, delete this exception statement from your
30     version.  If you delete this exception statement from all source
31     files in the program, then also delete it here.
32 */
33
34
35 #include "exceptions.h"
36 #include "local_time.h"
37 #include <boost/test/unit_test.hpp>
38
39
40 /** Check that dcp::LocalTime works */
41 BOOST_AUTO_TEST_CASE (local_time_basic_test)
42 {
43         /* Badly-formatted times */
44         BOOST_CHECK_THROW (dcp::LocalTime (""), dcp::TimeFormatError);
45         BOOST_CHECK_THROW (dcp::LocalTime ("XXX"), dcp::TimeFormatError);
46         BOOST_CHECK_THROW (dcp::LocalTime ("2013-01-05T18:06:59+04:0"), dcp::TimeFormatError);
47         BOOST_CHECK_THROW (dcp::LocalTime ("2013-01-05T18:06:59X04:00"), dcp::TimeFormatError);
48         BOOST_CHECK_THROW (dcp::LocalTime ("2013-01-05T18-06:59+04:00"), dcp::TimeFormatError);
49         BOOST_CHECK_THROW (dcp::LocalTime ("2013!01-05T18:06:59+04:00"), dcp::TimeFormatError);
50
51         /* Correctly-formatted */
52
53         {
54                 dcp::LocalTime t("2013-01-05T18:06:59");
55                 BOOST_CHECK_EQUAL(t._year, 2013);
56                 BOOST_CHECK_EQUAL(t._month, 1);
57                 BOOST_CHECK_EQUAL(t._day, 5);
58                 BOOST_CHECK_EQUAL(t._hour, 18);
59                 BOOST_CHECK_EQUAL(t._minute, 6);
60                 BOOST_CHECK_EQUAL(t._second, 59);
61                 BOOST_CHECK(t._offset == dcp::UTCOffset(0, 0));
62                 BOOST_CHECK_EQUAL(t.as_string(), "2013-01-05T18:06:59+00:00");
63         }
64
65         {
66                 dcp::LocalTime t ("2013-01-05T18:06:59+04:00");
67                 BOOST_CHECK_EQUAL (t._year, 2013);
68                 BOOST_CHECK_EQUAL (t._month, 1);
69                 BOOST_CHECK_EQUAL (t._day, 5);
70                 BOOST_CHECK_EQUAL (t._hour, 18);
71                 BOOST_CHECK_EQUAL (t._minute, 6);
72                 BOOST_CHECK_EQUAL (t._second, 59);
73                 BOOST_CHECK(t._offset == dcp::UTCOffset(4, 0));
74                 BOOST_CHECK_EQUAL (t.as_string(), "2013-01-05T18:06:59+04:00");
75         }
76
77         {
78                 dcp::LocalTime t ("2011-11-20T01:06:59-09:30");
79                 BOOST_CHECK_EQUAL (t._year, 2011);
80                 BOOST_CHECK_EQUAL (t._month, 11);
81                 BOOST_CHECK_EQUAL (t._day, 20);
82                 BOOST_CHECK_EQUAL (t._hour, 1);
83                 BOOST_CHECK_EQUAL (t._minute, 6);
84                 BOOST_CHECK_EQUAL (t._second, 59);
85                 BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
86                 BOOST_CHECK_EQUAL (t.as_string(), "2011-11-20T01:06:59-09:30");
87         }
88
89         {
90                 dcp::LocalTime t ("2011-11-20T01:06:59.456-09:30");
91                 BOOST_CHECK_EQUAL (t._year, 2011);
92                 BOOST_CHECK_EQUAL (t._month, 11);
93                 BOOST_CHECK_EQUAL (t._day, 20);
94                 BOOST_CHECK_EQUAL (t._hour, 1);
95                 BOOST_CHECK_EQUAL (t._minute, 6);
96                 BOOST_CHECK_EQUAL (t._second, 59);
97                 BOOST_CHECK_EQUAL (t._millisecond, 456);
98                 BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
99                 BOOST_CHECK_EQUAL (t.as_string(true), "2011-11-20T01:06:59.456-09:30");
100         }
101
102         {
103                 dcp::LocalTime t ("2011-11-20T01:06:59.456-09:30");
104                 BOOST_CHECK_EQUAL (t._year, 2011);
105                 BOOST_CHECK_EQUAL (t._month, 11);
106                 BOOST_CHECK_EQUAL (t._day, 20);
107                 BOOST_CHECK_EQUAL (t._hour, 1);
108                 BOOST_CHECK_EQUAL (t._minute, 6);
109                 BOOST_CHECK_EQUAL (t._second, 59);
110                 BOOST_CHECK_EQUAL (t._millisecond, 456);
111                 BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
112                 BOOST_CHECK_EQUAL (t.as_string(true, false), "2011-11-20T01:06:59.456");
113         }
114
115         {
116                 dcp::LocalTime t ("2011-11-20T01:06:59.456-09:30");
117                 BOOST_CHECK_EQUAL (t._year, 2011);
118                 BOOST_CHECK_EQUAL (t._month, 11);
119                 BOOST_CHECK_EQUAL (t._day, 20);
120                 BOOST_CHECK_EQUAL (t._hour, 1);
121                 BOOST_CHECK_EQUAL (t._minute, 6);
122                 BOOST_CHECK_EQUAL (t._second, 59);
123                 BOOST_CHECK_EQUAL (t._millisecond, 456);
124                 BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
125                 BOOST_CHECK_EQUAL (t.as_string(false, false), "2011-11-20T01:06:59");
126         }
127
128         {
129                 dcp::LocalTime t("2011-11-20T01:06:59.45678901-09:30");
130                 BOOST_CHECK_EQUAL(t._year, 2011);
131                 BOOST_CHECK_EQUAL(t._month, 11);
132                 BOOST_CHECK_EQUAL(t._day, 20);
133                 BOOST_CHECK_EQUAL(t._hour, 1);
134                 BOOST_CHECK_EQUAL(t._minute, 6);
135                 BOOST_CHECK_EQUAL(t._second, 59);
136                 /* The fractional seconds here is truncated rather than rounded, for better or worse */
137                 BOOST_CHECK_EQUAL(t._millisecond, 456);
138                 BOOST_CHECK(t._offset == dcp::UTCOffset(-9, -30));
139                 BOOST_CHECK_EQUAL(t.as_string(false, false), "2011-11-20T01:06:59");
140         }
141
142         {
143                 /* Construction from boost::posix_time::ptime */
144                 dcp::LocalTime b (boost::posix_time::time_from_string ("2002-01-20 19:03:56"));
145                 BOOST_CHECK_EQUAL (b._year, 2002);
146                 BOOST_CHECK_EQUAL (b._month, 1);
147                 BOOST_CHECK_EQUAL (b._day, 20);
148                 BOOST_CHECK_EQUAL (b._hour, 19);
149                 BOOST_CHECK_EQUAL (b._minute, 3);
150                 BOOST_CHECK_EQUAL (b._second, 56);
151         }
152
153         {
154                 /* Construction from boost::posix_time::ptime with milliseconds */
155                 dcp::LocalTime b (boost::posix_time::time_from_string ("2002-01-20 19:03:56.491"));
156                 BOOST_CHECK_EQUAL (b._year, 2002);
157                 BOOST_CHECK_EQUAL (b._month, 1);
158                 BOOST_CHECK_EQUAL (b._day, 20);
159                 BOOST_CHECK_EQUAL (b._hour, 19);
160                 BOOST_CHECK_EQUAL (b._minute, 3);
161                 BOOST_CHECK_EQUAL (b._second, 56);
162                 BOOST_CHECK_EQUAL (b._millisecond, 491);
163         }
164
165         {
166                 dcp::LocalTime b ("2015-11-18T19:26:45");
167                 BOOST_CHECK_EQUAL (b._year, 2015);
168                 BOOST_CHECK_EQUAL (b._month, 11);
169                 BOOST_CHECK_EQUAL (b._day, 18);
170                 BOOST_CHECK_EQUAL (b._hour, 19);
171                 BOOST_CHECK_EQUAL (b._minute, 26);
172                 BOOST_CHECK_EQUAL (b._second, 45);
173                 BOOST_CHECK_EQUAL (b._millisecond, 0);
174                 BOOST_CHECK(b._offset == dcp::UTCOffset());
175         }
176
177         /* Check negative times with non-zero timezone offset minutes */
178         {
179                 dcp::LocalTime t ("2013-01-05T18:06:59-04:30");
180                 BOOST_CHECK_EQUAL (t._year, 2013);
181                 BOOST_CHECK_EQUAL (t._month, 1);
182                 BOOST_CHECK_EQUAL (t._day, 5);
183                 BOOST_CHECK_EQUAL (t._hour, 18);
184                 BOOST_CHECK_EQUAL (t._minute, 6);
185                 BOOST_CHECK_EQUAL (t._second, 59);
186                 BOOST_CHECK(t._offset == dcp::UTCOffset(-4, -30));
187                 BOOST_CHECK_EQUAL (t.as_string(), "2013-01-05T18:06:59-04:30");
188         }
189 }
190
191
192 BOOST_AUTO_TEST_CASE (local_time_add_minutes_test)
193 {
194         {
195                 dcp::LocalTime t("2018-01-01T10:00:00+01:00");
196                 t.add_minutes (3);
197                 BOOST_CHECK_EQUAL (t.as_string(), "2018-01-01T10:03:00+01:00");
198         }
199
200         {
201                 dcp::LocalTime t("2018-01-01T10:00:15+01:00");
202                 t.add_minutes (3);
203                 BOOST_CHECK_EQUAL (t.as_string(), "2018-01-01T10:03:15+01:00");
204         }
205
206         {
207                 dcp::LocalTime t("2018-01-01T10:40:20+01:00");
208                 t.add_minutes (23);
209                 BOOST_CHECK_EQUAL (t.as_string(), "2018-01-01T11:03:20+01:00");
210         }
211
212         {
213                 dcp::LocalTime t("2018-01-01T10:40:20+01:00");
214                 t.add_minutes (123);
215                 BOOST_CHECK_EQUAL (t.as_string(), "2018-01-01T12:43:20+01:00");
216         }
217
218         {
219                 dcp::LocalTime t("2018-01-01T23:55:00+01:00");
220                 t.add_minutes (7);
221                 BOOST_CHECK_EQUAL (t.as_string(), "2018-01-02T00:02:00+01:00");
222         }
223
224         {
225                 dcp::LocalTime t("2018-01-31T23:55:00+01:00");
226                 t.add_minutes (7);
227                 BOOST_CHECK_EQUAL (t.as_string(), "2018-02-01T00:02:00+01:00");
228         }
229
230         {
231                 dcp::LocalTime t("2018-01-31T23:55:00.123");
232                 t.add_minutes (7);
233                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2018-02-01T00:02:00.123"));
234         }
235 }
236
237
238 BOOST_AUTO_TEST_CASE (local_time_add_months_test)
239 {
240         {
241                 dcp::LocalTime t("2013-06-23T18:06:59.123");
242                 t.add_months(-1);
243                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2013-05-23T18:06:59.123"));
244                 t.add_months(1);
245                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2013-06-23T18:06:59.123"));
246                 t.add_months(1);
247                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2013-07-23T18:06:59.123"));
248                 t.add_months(4);
249                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2013-11-23T18:06:59.123"));
250                 t.add_months(2);
251                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2014-01-23T18:06:59.123"));
252                 t.add_months(-14);
253                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2012-11-23T18:06:59.123"));
254                 t.add_months(14);
255                 BOOST_CHECK_EQUAL (t, dcp::LocalTime("2014-01-23T18:06:59.123"));
256         }
257
258         {
259                 dcp::LocalTime t("2018-01-30T11:00:00+01:00");
260                 t.add_months (1);
261                 BOOST_CHECK_EQUAL (t.as_string(), "2018-02-28T11:00:00+01:00");
262         }
263 }
264
265
266 BOOST_AUTO_TEST_CASE (local_time_from_asn1_utctime_test)
267 {
268         BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_utc_time("991231235952").as_string(), "1999-12-31T23:59:52+00:00");
269         BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_utc_time("210215165952").as_string(), "2021-02-15T16:59:52+00:00");
270 }
271
272
273 BOOST_AUTO_TEST_CASE (local_time_from_asn1_generalized_time_test)
274 {
275         BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_generalized_time("19991231235952").as_string(), "1999-12-31T23:59:52+00:00");
276         BOOST_CHECK_EQUAL (dcp::LocalTime::from_asn1_generalized_time("20210215165952").as_string(), "2021-02-15T16:59:52+00:00");
277 }
278
279
280 BOOST_AUTO_TEST_CASE(local_time_comparison_test)
281 {
282         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") < dcp::LocalTime("2014-01-01T10:05:00"));
283         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") < dcp::LocalTime("2015-01-01T10:00:00"));
284         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") < dcp::LocalTime("2014-01-01T11:00:00"));
285         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00") < dcp::LocalTime("2014-10-10T10:00:01"));
286         BOOST_CHECK(!(dcp::LocalTime("2014-10-10T10:00:00") < dcp::LocalTime("2014-10-10T10:00:00")));
287         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00+01:00") < dcp::LocalTime("2014-10-10T10:00:00"));
288         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00+01:30") < dcp::LocalTime("2014-10-10T10:00:00"));
289         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00+01:00") < dcp::LocalTime("2014-10-10T10:00:01+01:00"));
290         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") < dcp::LocalTime("2014-01-01T10:05:00"));
291         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00") < dcp::LocalTime("2014-10-10T10:00:00-01:30"));
292
293         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:05:00") > dcp::LocalTime("2014-01-01T10:00:00"));
294         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00-01:30") > dcp::LocalTime("2014-10-10T10:00:00"));
295         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:05:00") > dcp::LocalTime("2014-01-01T10:00:00"));
296         BOOST_CHECK(dcp::LocalTime("2015-01-01T10:00:00") > dcp::LocalTime("2014-01-01T10:00:00"));
297         BOOST_CHECK(dcp::LocalTime("2014-01-01T11:00:00") > dcp::LocalTime("2014-01-01T10:00:00"));
298         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:01") > dcp::LocalTime("2014-10-10T10:00:00"));
299         BOOST_CHECK(!(dcp::LocalTime("2014-10-10T10:00:00") > dcp::LocalTime("2014-10-10T10:00:00")));
300         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00") > dcp::LocalTime("2014-10-10T10:00:00+01:00"));
301         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:00") > dcp::LocalTime("2014-10-10T10:00:00+01:30"));
302         BOOST_CHECK(dcp::LocalTime("2014-10-10T10:00:01+01:00") > dcp::LocalTime("2014-10-10T10:00:00+01:00"));
303
304         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") != dcp::LocalTime("2014-01-01T10:05:00"));
305         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00") == dcp::LocalTime("2014-01-01T10:00:00"));
306         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00+02:00") == dcp::LocalTime("2014-01-01T08:00:00"));
307         BOOST_CHECK(dcp::LocalTime("2014-01-01T10:00:00+02:00") == dcp::LocalTime("2014-01-01T11:00:00+03:00"));
308 }