Skip to content

Commit 9259f79

Browse files
committed
tz: fix retrieval of past time zone transitions for America/Sao_Paulo
This bug likely exists for other time zones that have historical DST but have no DST presently. The problem here was that we were too strongly deferring to the POSIX time zone to compute the prior transition when the query appeared after all historical time zones. But that's only correct if the POSIX time zone has transitions at all. If it doesn't, then the most recent transition is the most recent historical transition. Fixes #309
1 parent 2b84020 commit 9259f79

File tree

6 files changed

+146
-1
lines changed

6 files changed

+146
-1
lines changed
Binary file not shown.
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
source: src/tz/tzif.rs
3+
expression: tzif_to_human_readable(&tzif_test.parse())
4+
---
5+
TIME ZONE NAME
6+
America/Sao_Paulo
7+
TIME ZONE VERSION
8+
2
9+
LOCAL TIME TYPES
10+
000: offset=-03:06:28 designation=LMT indicator=local/wall
11+
001: offset=-02 designation=-02 dst indicator=local/wall
12+
002: offset=-03 designation=-03 indicator=local/wall
13+
TRANSITIONS
14+
0000: -009999-01-02T01:59:59Z unix=-377705023201 wall=-009999-01-01T22:53:31 unambiguous type=0 -03:06:28 LMT
15+
0001: 1914-01-01T03:06:28Z unix=-1767214412 wall=1914-01-01T00:00:00 gap-until(1914-01-01T00:06:28) type=2 -03 -03
16+
0002: 1931-10-03T14:00:00Z unix=-1206957600 wall=1931-10-03T11:00:00 gap-until(1931-10-03T12:00:00) type=1 -02 -02 dst
17+
0003: 1932-04-01T02:00:00Z unix=-1191362400 wall=1932-03-31T23:00:00 fold-until(1932-04-01T00:00:00) type=2 -03 -03
18+
0004: 1932-10-03T03:00:00Z unix=-1175374800 wall=1932-10-03T00:00:00 gap-until(1932-10-03T01:00:00) type=1 -02 -02 dst
19+
0005: 1933-04-01T02:00:00Z unix=-1159826400 wall=1933-03-31T23:00:00 fold-until(1933-04-01T00:00:00) type=2 -03 -03
20+
0006: 1949-12-01T03:00:00Z unix=-633819600 wall=1949-12-01T00:00:00 gap-until(1949-12-01T01:00:00) type=1 -02 -02 dst
21+
0007: 1950-04-16T03:00:00Z unix=-622069200 wall=1950-04-16T00:00:00 fold-until(1950-04-16T01:00:00) type=2 -03 -03
22+
0008: 1950-12-01T03:00:00Z unix=-602283600 wall=1950-12-01T00:00:00 gap-until(1950-12-01T01:00:00) type=1 -02 -02 dst
23+
0009: 1951-04-01T02:00:00Z unix=-591832800 wall=1951-03-31T23:00:00 fold-until(1951-04-01T00:00:00) type=2 -03 -03
24+
0010: 1951-12-01T03:00:00Z unix=-570747600 wall=1951-12-01T00:00:00 gap-until(1951-12-01T01:00:00) type=1 -02 -02 dst
25+
0011: 1952-04-01T02:00:00Z unix=-560210400 wall=1952-03-31T23:00:00 fold-until(1952-04-01T00:00:00) type=2 -03 -03
26+
0012: 1952-12-01T03:00:00Z unix=-539125200 wall=1952-12-01T00:00:00 gap-until(1952-12-01T01:00:00) type=1 -02 -02 dst
27+
0013: 1953-03-01T02:00:00Z unix=-531352800 wall=1953-02-28T23:00:00 fold-until(1953-03-01T00:00:00) type=2 -03 -03
28+
0014: 1963-10-23T03:00:00Z unix=-195426000 wall=1963-10-23T00:00:00 gap-until(1963-10-23T01:00:00) type=1 -02 -02 dst
29+
0015: 1964-03-01T02:00:00Z unix=-184197600 wall=1964-02-29T23:00:00 fold-until(1964-03-01T00:00:00) type=2 -03 -03
30+
0016: 1965-01-31T03:00:00Z unix=-155163600 wall=1965-01-31T00:00:00 gap-until(1965-01-31T01:00:00) type=1 -02 -02 dst
31+
0017: 1965-03-31T02:00:00Z unix=-150069600 wall=1965-03-30T23:00:00 fold-until(1965-03-31T00:00:00) type=2 -03 -03
32+
0018: 1965-12-01T03:00:00Z unix=-128898000 wall=1965-12-01T00:00:00 gap-until(1965-12-01T01:00:00) type=1 -02 -02 dst
33+
0019: 1966-03-01T02:00:00Z unix=-121125600 wall=1966-02-28T23:00:00 fold-until(1966-03-01T00:00:00) type=2 -03 -03
34+
0020: 1966-11-01T03:00:00Z unix=-99954000 wall=1966-11-01T00:00:00 gap-until(1966-11-01T01:00:00) type=1 -02 -02 dst
35+
0021: 1967-03-01T02:00:00Z unix=-89589600 wall=1967-02-28T23:00:00 fold-until(1967-03-01T00:00:00) type=2 -03 -03
36+
0022: 1967-11-01T03:00:00Z unix=-68418000 wall=1967-11-01T00:00:00 gap-until(1967-11-01T01:00:00) type=1 -02 -02 dst
37+
0023: 1968-03-01T02:00:00Z unix=-57967200 wall=1968-02-29T23:00:00 fold-until(1968-03-01T00:00:00) type=2 -03 -03
38+
0024: 1985-11-02T03:00:00Z unix=499748400 wall=1985-11-02T00:00:00 gap-until(1985-11-02T01:00:00) type=1 -02 -02 dst
39+
0025: 1986-03-15T02:00:00Z unix=511236000 wall=1986-03-14T23:00:00 fold-until(1986-03-15T00:00:00) type=2 -03 -03
40+
0026: 1986-10-25T03:00:00Z unix=530593200 wall=1986-10-25T00:00:00 gap-until(1986-10-25T01:00:00) type=1 -02 -02 dst
41+
0027: 1987-02-14T02:00:00Z unix=540266400 wall=1987-02-13T23:00:00 fold-until(1987-02-14T00:00:00) type=2 -03 -03
42+
0028: 1987-10-25T03:00:00Z unix=562129200 wall=1987-10-25T00:00:00 gap-until(1987-10-25T01:00:00) type=1 -02 -02 dst
43+
0029: 1988-02-07T02:00:00Z unix=571197600 wall=1988-02-06T23:00:00 fold-until(1988-02-07T00:00:00) type=2 -03 -03
44+
0030: 1988-10-16T03:00:00Z unix=592974000 wall=1988-10-16T00:00:00 gap-until(1988-10-16T01:00:00) type=1 -02 -02 dst
45+
0031: 1989-01-29T02:00:00Z unix=602042400 wall=1989-01-28T23:00:00 fold-until(1989-01-29T00:00:00) type=2 -03 -03
46+
0032: 1989-10-15T03:00:00Z unix=624423600 wall=1989-10-15T00:00:00 gap-until(1989-10-15T01:00:00) type=1 -02 -02 dst
47+
0033: 1990-02-11T02:00:00Z unix=634701600 wall=1990-02-10T23:00:00 fold-until(1990-02-11T00:00:00) type=2 -03 -03
48+
0034: 1990-10-21T03:00:00Z unix=656478000 wall=1990-10-21T00:00:00 gap-until(1990-10-21T01:00:00) type=1 -02 -02 dst
49+
0035: 1991-02-17T02:00:00Z unix=666756000 wall=1991-02-16T23:00:00 fold-until(1991-02-17T00:00:00) type=2 -03 -03
50+
0036: 1991-10-20T03:00:00Z unix=687927600 wall=1991-10-20T00:00:00 gap-until(1991-10-20T01:00:00) type=1 -02 -02 dst
51+
0037: 1992-02-09T02:00:00Z unix=697600800 wall=1992-02-08T23:00:00 fold-until(1992-02-09T00:00:00) type=2 -03 -03
52+
0038: 1992-10-25T03:00:00Z unix=719982000 wall=1992-10-25T00:00:00 gap-until(1992-10-25T01:00:00) type=1 -02 -02 dst
53+
0039: 1993-01-31T02:00:00Z unix=728445600 wall=1993-01-30T23:00:00 fold-until(1993-01-31T00:00:00) type=2 -03 -03
54+
0040: 1993-10-17T03:00:00Z unix=750826800 wall=1993-10-17T00:00:00 gap-until(1993-10-17T01:00:00) type=1 -02 -02 dst
55+
0041: 1994-02-20T02:00:00Z unix=761709600 wall=1994-02-19T23:00:00 fold-until(1994-02-20T00:00:00) type=2 -03 -03
56+
0042: 1994-10-16T03:00:00Z unix=782276400 wall=1994-10-16T00:00:00 gap-until(1994-10-16T01:00:00) type=1 -02 -02 dst
57+
0043: 1995-02-19T02:00:00Z unix=793159200 wall=1995-02-18T23:00:00 fold-until(1995-02-19T00:00:00) type=2 -03 -03
58+
0044: 1995-10-15T03:00:00Z unix=813726000 wall=1995-10-15T00:00:00 gap-until(1995-10-15T01:00:00) type=1 -02 -02 dst
59+
0045: 1996-02-11T02:00:00Z unix=824004000 wall=1996-02-10T23:00:00 fold-until(1996-02-11T00:00:00) type=2 -03 -03
60+
0046: 1996-10-06T03:00:00Z unix=844570800 wall=1996-10-06T00:00:00 gap-until(1996-10-06T01:00:00) type=1 -02 -02 dst
61+
0047: 1997-02-16T02:00:00Z unix=856058400 wall=1997-02-15T23:00:00 fold-until(1997-02-16T00:00:00) type=2 -03 -03
62+
0048: 1997-10-06T03:00:00Z unix=876106800 wall=1997-10-06T00:00:00 gap-until(1997-10-06T01:00:00) type=1 -02 -02 dst
63+
0049: 1998-03-01T02:00:00Z unix=888717600 wall=1998-02-28T23:00:00 fold-until(1998-03-01T00:00:00) type=2 -03 -03
64+
0050: 1998-10-11T03:00:00Z unix=908074800 wall=1998-10-11T00:00:00 gap-until(1998-10-11T01:00:00) type=1 -02 -02 dst
65+
0051: 1999-02-21T02:00:00Z unix=919562400 wall=1999-02-20T23:00:00 fold-until(1999-02-21T00:00:00) type=2 -03 -03
66+
0052: 1999-10-03T03:00:00Z unix=938919600 wall=1999-10-03T00:00:00 gap-until(1999-10-03T01:00:00) type=1 -02 -02 dst
67+
0053: 2000-02-27T02:00:00Z unix=951616800 wall=2000-02-26T23:00:00 fold-until(2000-02-27T00:00:00) type=2 -03 -03
68+
0054: 2000-10-08T03:00:00Z unix=970974000 wall=2000-10-08T00:00:00 gap-until(2000-10-08T01:00:00) type=1 -02 -02 dst
69+
0055: 2001-02-18T02:00:00Z unix=982461600 wall=2001-02-17T23:00:00 fold-until(2001-02-18T00:00:00) type=2 -03 -03
70+
0056: 2001-10-14T03:00:00Z unix=1003028400 wall=2001-10-14T00:00:00 gap-until(2001-10-14T01:00:00) type=1 -02 -02 dst
71+
0057: 2002-02-17T02:00:00Z unix=1013911200 wall=2002-02-16T23:00:00 fold-until(2002-02-17T00:00:00) type=2 -03 -03
72+
0058: 2002-11-03T03:00:00Z unix=1036292400 wall=2002-11-03T00:00:00 gap-until(2002-11-03T01:00:00) type=1 -02 -02 dst
73+
0059: 2003-02-16T02:00:00Z unix=1045360800 wall=2003-02-15T23:00:00 fold-until(2003-02-16T00:00:00) type=2 -03 -03
74+
0060: 2003-10-19T03:00:00Z unix=1066532400 wall=2003-10-19T00:00:00 gap-until(2003-10-19T01:00:00) type=1 -02 -02 dst
75+
0061: 2004-02-15T02:00:00Z unix=1076810400 wall=2004-02-14T23:00:00 fold-until(2004-02-15T00:00:00) type=2 -03 -03
76+
0062: 2004-11-02T03:00:00Z unix=1099364400 wall=2004-11-02T00:00:00 gap-until(2004-11-02T01:00:00) type=1 -02 -02 dst
77+
0063: 2005-02-20T02:00:00Z unix=1108864800 wall=2005-02-19T23:00:00 fold-until(2005-02-20T00:00:00) type=2 -03 -03
78+
0064: 2005-10-16T03:00:00Z unix=1129431600 wall=2005-10-16T00:00:00 gap-until(2005-10-16T01:00:00) type=1 -02 -02 dst
79+
0065: 2006-02-19T02:00:00Z unix=1140314400 wall=2006-02-18T23:00:00 fold-until(2006-02-19T00:00:00) type=2 -03 -03
80+
0066: 2006-11-05T03:00:00Z unix=1162695600 wall=2006-11-05T00:00:00 gap-until(2006-11-05T01:00:00) type=1 -02 -02 dst
81+
0067: 2007-02-25T02:00:00Z unix=1172368800 wall=2007-02-24T23:00:00 fold-until(2007-02-25T00:00:00) type=2 -03 -03
82+
0068: 2007-10-14T03:00:00Z unix=1192330800 wall=2007-10-14T00:00:00 gap-until(2007-10-14T01:00:00) type=1 -02 -02 dst
83+
0069: 2008-02-17T02:00:00Z unix=1203213600 wall=2008-02-16T23:00:00 fold-until(2008-02-17T00:00:00) type=2 -03 -03
84+
0070: 2008-10-19T03:00:00Z unix=1224385200 wall=2008-10-19T00:00:00 gap-until(2008-10-19T01:00:00) type=1 -02 -02 dst
85+
0071: 2009-02-15T02:00:00Z unix=1234663200 wall=2009-02-14T23:00:00 fold-until(2009-02-15T00:00:00) type=2 -03 -03
86+
0072: 2009-10-18T03:00:00Z unix=1255834800 wall=2009-10-18T00:00:00 gap-until(2009-10-18T01:00:00) type=1 -02 -02 dst
87+
0073: 2010-02-21T02:00:00Z unix=1266717600 wall=2010-02-20T23:00:00 fold-until(2010-02-21T00:00:00) type=2 -03 -03
88+
0074: 2010-10-17T03:00:00Z unix=1287284400 wall=2010-10-17T00:00:00 gap-until(2010-10-17T01:00:00) type=1 -02 -02 dst
89+
0075: 2011-02-20T02:00:00Z unix=1298167200 wall=2011-02-19T23:00:00 fold-until(2011-02-20T00:00:00) type=2 -03 -03
90+
0076: 2011-10-16T03:00:00Z unix=1318734000 wall=2011-10-16T00:00:00 gap-until(2011-10-16T01:00:00) type=1 -02 -02 dst
91+
0077: 2012-02-26T02:00:00Z unix=1330221600 wall=2012-02-25T23:00:00 fold-until(2012-02-26T00:00:00) type=2 -03 -03
92+
0078: 2012-10-21T03:00:00Z unix=1350788400 wall=2012-10-21T00:00:00 gap-until(2012-10-21T01:00:00) type=1 -02 -02 dst
93+
0079: 2013-02-17T02:00:00Z unix=1361066400 wall=2013-02-16T23:00:00 fold-until(2013-02-17T00:00:00) type=2 -03 -03
94+
0080: 2013-10-20T03:00:00Z unix=1382238000 wall=2013-10-20T00:00:00 gap-until(2013-10-20T01:00:00) type=1 -02 -02 dst
95+
0081: 2014-02-16T02:00:00Z unix=1392516000 wall=2014-02-15T23:00:00 fold-until(2014-02-16T00:00:00) type=2 -03 -03
96+
0082: 2014-10-19T03:00:00Z unix=1413687600 wall=2014-10-19T00:00:00 gap-until(2014-10-19T01:00:00) type=1 -02 -02 dst
97+
0083: 2015-02-22T02:00:00Z unix=1424570400 wall=2015-02-21T23:00:00 fold-until(2015-02-22T00:00:00) type=2 -03 -03
98+
0084: 2015-10-18T03:00:00Z unix=1445137200 wall=2015-10-18T00:00:00 gap-until(2015-10-18T01:00:00) type=1 -02 -02 dst
99+
0085: 2016-02-21T02:00:00Z unix=1456020000 wall=2016-02-20T23:00:00 fold-until(2016-02-21T00:00:00) type=2 -03 -03
100+
0086: 2016-10-16T03:00:00Z unix=1476586800 wall=2016-10-16T00:00:00 gap-until(2016-10-16T01:00:00) type=1 -02 -02 dst
101+
0087: 2017-02-19T02:00:00Z unix=1487469600 wall=2017-02-18T23:00:00 fold-until(2017-02-19T00:00:00) type=2 -03 -03
102+
0088: 2017-10-15T03:00:00Z unix=1508036400 wall=2017-10-15T00:00:00 gap-until(2017-10-15T01:00:00) type=1 -02 -02 dst
103+
0089: 2018-02-18T02:00:00Z unix=1518919200 wall=2018-02-17T23:00:00 fold-until(2018-02-18T00:00:00) type=2 -03 -03
104+
0090: 2018-11-04T03:00:00Z unix=1541300400 wall=2018-11-04T00:00:00 gap-until(2018-11-04T01:00:00) type=1 -02 -02 dst
105+
0091: 2019-02-17T02:00:00Z unix=1550368800 wall=2019-02-16T23:00:00 fold-until(2019-02-17T00:00:00) type=2 -03 -03
106+
POSIX TIME ZONE STRING
107+
<-03>3

src/tz/testdata.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ pub(crate) static TZIF_TEST_FILES: &[TzifTestFile] = &[
6464
name: "Australia/Sydney/RHEL8",
6565
data: include_bytes!("testdata/australia-sydney-rhel8.tzif"),
6666
},
67+
// I added this to test finding previous time zone transitions in a time
68+
// zone that had somewhat recently eliminated DST. The bug was that Jiff
69+
// wasn't reporting *any* previous time zone transitions.
70+
TzifTestFile {
71+
name: "America/Sao_Paulo",
72+
data: include_bytes!("testdata/america-sao-paulo.tzif"),
73+
},
6774
TzifTestFile { name: "UTC", data: include_bytes!("testdata/utc.tzif") },
6875
];
6976

1.4 KB
Binary file not shown.

src/tz/timezone.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3491,8 +3491,17 @@ mod tests {
34913491
("1989-10-25 01Z", Some("1989-03-26 01Z")),
34923492
],
34933493
),
3494+
(
3495+
// Sao Paulo eliminated DST in 2019, so the previous transition
3496+
// from 2024 is several years back.
3497+
"America/Sao_Paulo",
3498+
&[("2024-03-10 08Z", Some("2019-02-17 02Z"))],
3499+
),
34943500
];
34953501
for &(tzname, prev_trans) in tests {
3502+
if tzname != "America/Sao_Paulo" {
3503+
continue;
3504+
}
34963505
let test_file = TzifTestFile::get(tzname);
34973506
let tz = TimeZone::tzif(test_file.name, test_file.data).unwrap();
34983507
for (given, expected) in prev_trans {
@@ -3572,6 +3581,12 @@ mod tests {
35723581
("1990-10-28 01Z", Some("1991-03-31 01Z")),
35733582
],
35743583
),
3584+
(
3585+
// Sao Paulo eliminated DST in 2019, so the next transition
3586+
// from 2024 no longer exists.
3587+
"America/Sao_Paulo",
3588+
&[("2024-03-10 08Z", None)],
3589+
),
35753590
];
35763591
for &(tzname, next_trans) in tests {
35773592
let test_file = TzifTestFile::get(tzname);

src/tz/tzif.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,16 @@ impl<
411411
// What if this returns `None` though? I'm not sure in which
412412
// cases that could matter, and I think it might be a violation
413413
// of the TZif format if it does.
414-
return posix_tz.previous_transition(ts);
414+
//
415+
// It can return `None`! In the case of a time zone that
416+
// has eliminated DST, it might have historical time zone
417+
// transitions but a POSIX time zone without DST. (For example,
418+
// `America/Sao_Paulo`.) And thus, this would return `None`.
419+
// So if it does, we pretend as if the POSIX time zone doesn't
420+
// exist.
421+
if let Some(trans) = posix_tz.previous_transition(ts) {
422+
return Some(trans);
423+
}
415424
}
416425
index
417426
} else {
@@ -454,6 +463,13 @@ impl<
454463
// What if this returns `None` though? I'm not sure in which
455464
// cases that could matter, and I think it might be a violation
456465
// of the TZif format if it does.
466+
//
467+
// In the "previous" case above, this could return `None` even
468+
// when there are historical time zone transitions in the case
469+
// of a time zone eliminating DST (e.g., `America/Sao_Paulo`).
470+
// But unlike the previous case, if we get `None` here, then
471+
// that is the real answer because there are no other known
472+
// future time zone transitions.
457473
return posix_tz.next_transition(ts);
458474
}
459475
self.timestamps().len() - 1

0 commit comments

Comments
 (0)