@@ -68,14 +68,19 @@ impl TZif {
6868 // If there's no POSIX TZ string, use the last offset.
6969 // There's not much else we can do.
7070 . unwrap_or_else ( || {
71- let ( offset , _ ) = self
71+ let ( prev_offset , last_shift ) = self
7272 . offsets_by_local
7373 . last ( )
74- // Safe : We've ensured during parsing that there's at least one entry
74+ // SAFETY : We've ensured during parsing that there's at least one entry
7575 // if there's no POSIX TZ string.
7676 . unwrap ( )
7777 . 1 ;
78- Ambiguity :: Unambiguous ( offset)
78+ Ambiguity :: Unambiguous (
79+ prev_offset
80+ . shift ( last_shift)
81+ // SAFETY: last_shift was calculated from prev_offset itself
82+ . unwrap ( ) ,
83+ )
7984 } )
8085 }
8186}
@@ -268,7 +273,8 @@ fn load_transitions(
268273 offsets : & [ Offset ] ,
269274 indices : & [ u8 ] ,
270275) -> Option < Vec < ( EpochSecs , Offset ) > > {
271- let mut result = Vec :: with_capacity ( indices. len ( ) ) ;
276+ let mut result = Vec :: with_capacity ( indices. len ( ) + 1 ) ;
277+ result. push ( ( EpochSecs :: MIN , * offsets. first ( ) ?) ) ; // Ensure correct initial offset
272278 for ( & idx, & epoch) in indices. iter ( ) . zip ( transition_times) {
273279 let & offset = offsets. get ( usize:: from ( idx) ) ?;
274280 result. push ( ( epoch, offset) ) ;
@@ -393,12 +399,12 @@ mod tests {
393399 #[ test]
394400 fn test_no_magic_header ( ) {
395401 // empty
396- assert_eq ! ( parse( b"" , "Foo " ) . unwrap_err( ) , ErrorCause :: Header ) ;
402+ assert_eq ! ( parse( b"" , "" ) . unwrap_err( ) , ErrorCause :: Header ) ;
397403 // too small
398- assert_eq ! ( parse( b"TZi" , "Foo " ) . unwrap_err( ) , ErrorCause :: Header ) ;
404+ assert_eq ! ( parse( b"TZi" , "" ) . unwrap_err( ) , ErrorCause :: Header ) ;
399405 // wrong magic value
400406 assert_eq ! (
401- parse( b"this-is-not-tzif-file" , "Foo " ) . unwrap_err( ) ,
407+ parse( b"this-is-not-tzif-file" , "" ) . unwrap_err( ) ,
402408 ErrorCause :: Header
403409 ) ;
404410 }
@@ -430,8 +436,11 @@ mod tests {
430436 #[ test]
431437 fn test_utc ( ) {
432438 const TZ_UTC : & [ u8 ] = include_bytes ! ( "../../tests/tzif/UTC.tzif" ) ;
433- let tzif = parse ( TZ_UTC , "UTC" ) . unwrap ( ) ;
434- assert_eq ! ( tzif. offsets_by_utc, & [ ] ) ;
439+ let tzif = parse ( TZ_UTC , "" ) . unwrap ( ) ;
440+ assert_eq ! (
441+ tzif. offsets_by_utc,
442+ & [ ( EpochSecs :: MIN , 0 . try_into( ) . unwrap( ) ) ]
443+ ) ;
435444 assert_eq ! ( tzif. end, posix:: parse( b"UTC0" ) ) ;
436445
437446 assert_eq ! (
@@ -447,8 +456,11 @@ mod tests {
447456 #[ test]
448457 fn test_fixed ( ) {
449458 const TZ_FIXED : & [ u8 ] = include_bytes ! ( "../../tests/tzif/GMT-13.tzif" ) ;
450- let tzif = parse ( TZ_FIXED , "GMT-13" ) . unwrap ( ) ;
451- assert_eq ! ( tzif. offsets_by_utc, & [ ] ) ;
459+ let tzif = parse ( TZ_FIXED , "" ) . unwrap ( ) ;
460+ assert_eq ! (
461+ tzif. offsets_by_utc,
462+ & [ ( EpochSecs :: MIN , ( 13 * 3_600 ) . try_into( ) . unwrap( ) ) ]
463+ ) ;
452464 assert_eq ! ( tzif. end, posix:: parse( b"<+13>-13" ) ) ;
453465
454466 assert_eq ! (
@@ -465,7 +477,7 @@ mod tests {
465477 fn test_v1 ( ) {
466478 // A TZif file using the old version 1 format.
467479 const TZ_V1 : & [ u8 ] = include_bytes ! ( "../../tests/tzif/Paris_v1.tzif" ) ;
468- let tzif = parse ( TZ_V1 , "Europe/Paris " ) . unwrap ( ) ;
480+ let tzif = parse ( TZ_V1 , "" ) . unwrap ( ) ;
469481 assert ! ( !tzif. offsets_by_utc. is_empty( ) ) ;
470482 assert_eq ! ( tzif. end, None ) ;
471483
@@ -474,13 +486,17 @@ mod tests {
474486 tzif. offset_for_instant( EpochSecs :: new_unchecked( 3155760000 ) ) ,
475487 3600 . try_into( ) . unwrap( )
476488 ) ;
489+ assert_eq ! (
490+ tzif. ambiguity_for_local( EpochSecs :: new_unchecked( 3155760000 ) ) ,
491+ unambig( 3600 )
492+ ) ;
477493 }
478494
479495 // Thanks to Jiff for the test tzif file
480496 #[ test]
481497 fn test_clamp_transitions_to_range ( ) {
482498 const TZ_OUT_OF_RANGE : & [ u8 ] = include_bytes ! ( "../../tests/tzif/Sydney_widerange.tzif" ) ;
483- let tzif = parse ( TZ_OUT_OF_RANGE , "Australia/Sydney " ) . unwrap ( ) ;
499+ let tzif = parse ( TZ_OUT_OF_RANGE , "" ) . unwrap ( ) ;
484500 assert ! ( !tzif. offsets_by_utc. is_empty( ) ) ;
485501 assert_eq ! (
486502 tzif. offset_for_instant( EpochSecs :: MIN ) ,
@@ -492,10 +508,20 @@ mod tests {
492508 ) ;
493509 }
494510
511+ #[ test]
512+ fn test_implicit_initial_offset ( ) {
513+ const TZ_HON : & [ u8 ] = include_bytes ! ( "../../tests/tzif/Honolulu.tzif" ) ;
514+ let tzif = parse ( TZ_HON , "" ) . unwrap ( ) ;
515+ assert_eq ! (
516+ tzif. offset_for_instant( EpochSecs :: new_unchecked( -3_000_000_000 ) ) ,
517+ Offset :: new_unchecked( -37886 ) ,
518+ ) ;
519+ }
520+
495521 #[ test]
496522 fn test_last_transition_is_gap ( ) {
497523 const TZ_HON : & [ u8 ] = include_bytes ! ( "../../tests/tzif/Honolulu.tzif" ) ;
498- let tzif = parse ( TZ_HON , "Pacific/Honolulu " ) . unwrap ( ) ;
524+ let tzif = parse ( TZ_HON , "" ) . unwrap ( ) ;
499525 assert_eq ! ( tzif. end, posix:: parse( b"HST10" ) ) ;
500526 assert_eq ! (
501527 tzif. offset_for_instant( EpochSecs :: new_unchecked( -712150201 ) ) ,
@@ -535,7 +561,7 @@ mod tests {
535561 #[ test]
536562 fn test_typical_tzif_example ( ) {
537563 const TZ_AMS : & [ u8 ] = include_bytes ! ( "../../tests/tzif/Amsterdam.tzif" ) ;
538- let tzif = parse ( TZ_AMS , "Europe/Amsterdam " ) . unwrap ( ) ;
564+ let tzif = parse ( TZ_AMS , "" ) . unwrap ( ) ;
539565 assert_eq ! ( tzif. end, posix:: parse( b"CET-1CEST,M3.5.0,M10.5.0/3" ) ) ;
540566
541567 let utc_cases = & [
0 commit comments