mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-14 17:03:28 +00:00
Allow for only a single positive leap second.
Mercury currently allows for two positive leap seconds per minute, presumably
following earlier versions of the C standard (e.g. C90). This is based on
an erroneous understanding of how UTC is defined and was corrected in C99.
(UTC allows a maximum of one leap second, positive or negative, per minute.)
library/calendar.m:
library/time.m:
Allow only a single positive leap second per minute.
NEWS.md:
Announce the above change.
tests/hard_coded/calendar_date_time.conv.{m,exp}:
Update this test.
This commit is contained in:
8
NEWS.md
8
NEWS.md
@@ -246,6 +246,9 @@ Changes to the Mercury standard library
|
||||
- func `det_date_from_string/1` (replacement: `det_date_time_from_string/1`)
|
||||
- func `date_to_string/1` (replacement: `date_time_to_string/1`)
|
||||
|
||||
* `date_time/0` and `duration/0` values now only allow for a single positive
|
||||
leap second for any given minute.
|
||||
|
||||
* The following functions and predicates have been added:
|
||||
|
||||
- pred `init_date_time/8`
|
||||
@@ -1424,6 +1427,11 @@ Changes to the Mercury standard library
|
||||
- pred `spawn_native_joinable/5`
|
||||
- pred `join_thread/4`
|
||||
|
||||
### Changes to the `time` module
|
||||
|
||||
* The `tm_sec` field of the `tm/0` type now only allows for a single positive
|
||||
leap second for any given minute.
|
||||
|
||||
### Changes to the `tree_bitset` module
|
||||
|
||||
* The following predicates and functions have been added:
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
:- type day_of_month == int. % 1 .. 31 depending on the month and year
|
||||
:- type hour == int. % 0 .. 23
|
||||
:- type minute == int. % 0 .. 59
|
||||
:- type second == int. % 0 .. 61 (60 and 61 are for leap seconds)
|
||||
:- type second == int. % 0 .. 60 (60 is for a positive leap second)
|
||||
:- type microsecond == int. % 0 .. 999,999
|
||||
|
||||
:- type month
|
||||
@@ -165,8 +165,8 @@
|
||||
%
|
||||
% - Minute is in the range 0 .. 59
|
||||
%
|
||||
% - Second is in the range 0 .. 61
|
||||
% (to account for up to two leap seconds being added in a year)
|
||||
% - Second is in the range 0 .. 60
|
||||
% (to account for one positive leap second being added to a day)
|
||||
%
|
||||
% - MicroSecond is in the range 0 .. 999,999
|
||||
%
|
||||
@@ -313,9 +313,9 @@
|
||||
% - Adding -1 year to February 29, 2020 gives February 28, 2019
|
||||
%
|
||||
% Note on leap seconds: although individual dates can represent times
|
||||
% with leap seconds (seconds 60-61), durations ignore them. A day is
|
||||
% with leap seconds (second 60), durations ignore them. A day is
|
||||
% always treated as exactly 86,400 seconds, even though UTC days
|
||||
% containing leap seconds are 86,401 or 86,402 seconds long.
|
||||
% containing leap seconds are 86,399 or 86,401 seconds long.
|
||||
%
|
||||
% Durations are stored internally using four components only: months, days,
|
||||
% seconds and microseconds. When a duration is constructed by
|
||||
@@ -774,7 +774,7 @@ init_date_time(Year, Month, Day, Hour, Minute, Second, MicroSecond,
|
||||
Minute >= 0,
|
||||
Minute < 60,
|
||||
Second >= 0,
|
||||
Second < 62,
|
||||
Second < 61,
|
||||
MicroSecond >= 0,
|
||||
MicroSecond < 1000000,
|
||||
DateTime = date_time(Year, month_to_int(Month), Day, Hour, Minute, Second,
|
||||
@@ -843,7 +843,7 @@ date_time_from_string(Str, Date) :-
|
||||
Minute =< 59,
|
||||
read_char((:), !Chars),
|
||||
read_int_and_num_chars(Second, 2, !Chars),
|
||||
Second < 62,
|
||||
Second < 61,
|
||||
read_microseconds(MicroSecond, !Chars),
|
||||
!.Chars = [],
|
||||
Date = date_time(Year, Month, Day, Hour, Minute, Second, MicroSecond)
|
||||
|
||||
@@ -71,8 +71,8 @@
|
||||
tm_mday :: int, % MonthDay (1-31)
|
||||
tm_hour :: int, % Hours (after midnight, 0-23)
|
||||
tm_min :: int, % Minutes (0-59)
|
||||
tm_sec :: int, % Seconds (0-61)
|
||||
% (60 and 61 are for leap seconds)
|
||||
tm_sec :: int, % Seconds (0-60)
|
||||
% (60 allows for a positive leap second)
|
||||
tm_yday :: int, % YearDay (number since Jan 1st, 0-365)
|
||||
tm_wday :: int, % WeekDay (number since Sunday, 0-6)
|
||||
tm_dst :: maybe(dst) % IsDST (is DST applicable, and if so,
|
||||
|
||||
@@ -31,7 +31,6 @@ date_time_from_string("2024-12-31 00:00:00") ===> TEST PASSED (accepted: date_ti
|
||||
date_time_from_string("2024-01-01 00:00:00") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 0))
|
||||
date_time_from_string("2024-01-01 23:59:59") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 23, 59, 59, 0))
|
||||
date_time_from_string("2024-01-01 00:00:60") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 60, 0))
|
||||
date_time_from_string("2024-01-01 00:00:61") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 61, 0))
|
||||
date_time_from_string("2024-01-01 00:00:00.1") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 100000))
|
||||
date_time_from_string("2024-01-01 00:00:00.12") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 120000))
|
||||
date_time_from_string("2024-01-01 00:00:00.123") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 123000))
|
||||
@@ -40,7 +39,7 @@ date_time_from_string("2024-01-01 00:00:00.12345") ===> TEST PASSED (accepted: d
|
||||
date_time_from_string("2024-01-01 00:00:00.123456") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 123456))
|
||||
date_time_from_string("2024-01-01 00:00:00.000001") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 1))
|
||||
date_time_from_string("2024-01-01 00:00:00.999999") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 999999))
|
||||
date_time_from_string("2024-12-31 23:59:61.999999") ===> TEST PASSED (accepted: date_time(2024, 12, 31, 23, 59, 61, 999999))
|
||||
date_time_from_string("2024-12-31 23:59:60.999999") ===> TEST PASSED (accepted: date_time(2024, 12, 31, 23, 59, 60, 999999))
|
||||
date_time_from_string("1970-01-01 00:00:00") ===> TEST PASSED (accepted: date_time(1970, 1, 1, 0, 0, 0, 0))
|
||||
date_time_from_string("1582-10-15 00:00:00") ===> TEST PASSED (accepted: date_time(1582, 10, 15, 0, 0, 0, 0))
|
||||
date_time_from_string("2024-01-01 00:00:00.10") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 100000): to-string: "2024-01-01 00:00:00.1"))
|
||||
@@ -86,7 +85,7 @@ date_time_from_string("1900-02-29 00:00:00") ===> TEST PASSED (rejected: Feb 29
|
||||
date_time_from_string("2024-04-31 00:00:00") ===> TEST PASSED (rejected: day 31 in a 30-day month)
|
||||
date_time_from_string("2024-01-01 24:00:00") ===> TEST PASSED (rejected: hour 24)
|
||||
date_time_from_string("2024-01-01 00:60:00") ===> TEST PASSED (rejected: minute 60)
|
||||
date_time_from_string("2024-01-01 00:00:62") ===> TEST PASSED (rejected: second 62)
|
||||
date_time_from_string("2024-01-01 00:00:61") ===> TEST PASSED (rejected: second 61)
|
||||
date_time_from_string("2024-01-01 00:00:00.") ===> TEST PASSED (rejected: trailing dot with no digits)
|
||||
date_time_from_string("2024-01-01 00:00:00.1234567") ===> TEST PASSED (rejected: seven fractional digits)
|
||||
date_time_from_string("-01-01 00:00:00") ===> TEST PASSED (rejected: negative sign but only two-digit year)
|
||||
@@ -149,7 +148,6 @@ det_date_time_from_string("2024-12-31 00:00:00") ===> TEST PASSED (accepted: dat
|
||||
det_date_time_from_string("2024-01-01 00:00:00") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 0))
|
||||
det_date_time_from_string("2024-01-01 23:59:59") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 23, 59, 59, 0))
|
||||
det_date_time_from_string("2024-01-01 00:00:60") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 60, 0))
|
||||
det_date_time_from_string("2024-01-01 00:00:61") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 61, 0))
|
||||
det_date_time_from_string("2024-01-01 00:00:00.1") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 100000))
|
||||
det_date_time_from_string("2024-01-01 00:00:00.12") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 120000))
|
||||
det_date_time_from_string("2024-01-01 00:00:00.123") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 123000))
|
||||
@@ -158,7 +156,7 @@ det_date_time_from_string("2024-01-01 00:00:00.12345") ===> TEST PASSED (accepte
|
||||
det_date_time_from_string("2024-01-01 00:00:00.123456") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 123456))
|
||||
det_date_time_from_string("2024-01-01 00:00:00.000001") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 1))
|
||||
det_date_time_from_string("2024-01-01 00:00:00.999999") ===> TEST PASSED (accepted: date_time(2024, 1, 1, 0, 0, 0, 999999))
|
||||
det_date_time_from_string("2024-12-31 23:59:61.999999") ===> TEST PASSED (accepted: date_time(2024, 12, 31, 23, 59, 61, 999999))
|
||||
det_date_time_from_string("2024-12-31 23:59:60.999999") ===> TEST PASSED (accepted: date_time(2024, 12, 31, 23, 59, 60, 999999))
|
||||
det_date_time_from_string("1970-01-01 00:00:00") ===> TEST PASSED (accepted: date_time(1970, 1, 1, 0, 0, 0, 0))
|
||||
det_date_time_from_string("1582-10-15 00:00:00") ===> TEST PASSED (accepted: date_time(1582, 10, 15, 0, 0, 0, 0))
|
||||
|
||||
@@ -192,7 +190,7 @@ det_date_time_from_string("1900-02-29 00:00:00") ===> TEST PASSED (exception: Fe
|
||||
det_date_time_from_string("2024-04-31 00:00:00") ===> TEST PASSED (exception: day 31 in a 30-day month)
|
||||
det_date_time_from_string("2024-01-01 24:00:00") ===> TEST PASSED (exception: hour 24)
|
||||
det_date_time_from_string("2024-01-01 00:60:00") ===> TEST PASSED (exception: minute 60)
|
||||
det_date_time_from_string("2024-01-01 00:00:62") ===> TEST PASSED (exception: second 62)
|
||||
det_date_time_from_string("2024-01-01 00:00:61") ===> TEST PASSED (exception: second 61)
|
||||
det_date_time_from_string("2024-01-01 00:00:00.") ===> TEST PASSED (exception: trailing dot with no digits)
|
||||
det_date_time_from_string("2024-01-01 00:00:00.1234567") ===> TEST PASSED (exception: seven fractional digits)
|
||||
det_date_time_from_string("-01-01 00:00:00") ===> TEST PASSED (exception: negative sign but only two-digit year)
|
||||
|
||||
@@ -204,7 +204,6 @@ valid_date_times = [
|
||||
dt_conv_test("midnight", "2024-01-01 00:00:00"),
|
||||
dt_conv_test("last second of the day", "2024-01-01 23:59:59"),
|
||||
dt_conv_test("leap second", "2024-01-01 00:00:60"),
|
||||
dt_conv_test("double leap second", "2024-01-01 00:00:61"),
|
||||
|
||||
dt_conv_test("one fractional digit", "2024-01-01 00:00:00.1"),
|
||||
dt_conv_test("two fractional digits", "2024-01-01 00:00:00.12"),
|
||||
@@ -215,7 +214,7 @@ valid_date_times = [
|
||||
dt_conv_test("smallest nonzero microsecond", "2024-01-01 00:00:00.000001"),
|
||||
dt_conv_test("largest microsecond value", "2024-01-01 00:00:00.999999"),
|
||||
|
||||
dt_conv_test("all maximum", "2024-12-31 23:59:61.999999"),
|
||||
dt_conv_test("all maximum", "2024-12-31 23:59:60.999999"),
|
||||
dt_conv_test("Unix epoch", "1970-01-01 00:00:00"),
|
||||
dt_conv_test("first day of the Gregorian calendar",
|
||||
"1582-10-15 00:00:00")
|
||||
@@ -287,7 +286,7 @@ invalid_date_times = [
|
||||
dt_conv_test("day 31 in a 30-day month", "2024-04-31 00:00:00"),
|
||||
dt_conv_test("hour 24", "2024-01-01 24:00:00"),
|
||||
dt_conv_test("minute 60", "2024-01-01 00:60:00"),
|
||||
dt_conv_test("second 62", "2024-01-01 00:00:62"),
|
||||
dt_conv_test("second 61", "2024-01-01 00:00:61"),
|
||||
|
||||
dt_conv_test("trailing dot with no digits", "2024-01-01 00:00:00."),
|
||||
dt_conv_test("seven fractional digits", "2024-01-01 00:00:00.1234567"),
|
||||
|
||||
Reference in New Issue
Block a user