@@ -339,6 +339,227 @@ mod relative {
339339 }
340340}
341341
342+ /// Tests for compact ISO8601 formats (YYYYMMDDTHHMMSS variants)
343+ /// These formats are parsed by gix-date but may not be universally
344+ /// supported across all Git versions, so they have dedicated unit tests
345+ /// rather than baseline tests.
346+ mod compact_iso8601 {
347+ use gix_date:: Time ;
348+
349+ #[ test]
350+ fn full_format ( ) {
351+ // 20080214T203045 = Feb 14, 2008 20:30:45 UTC
352+ assert_eq ! (
353+ gix_date:: parse( "20080214T203045" , None ) . unwrap( ) ,
354+ Time {
355+ seconds: 1203021045 ,
356+ offset: 0 ,
357+ } ,
358+ ) ;
359+ }
360+
361+ #[ test]
362+ fn with_colons_in_time ( ) {
363+ // 20080214T20:30:45 = Feb 14, 2008 20:30:45 UTC
364+ assert_eq ! (
365+ gix_date:: parse( "20080214T20:30:45" , None ) . unwrap( ) ,
366+ Time {
367+ seconds: 1203021045 ,
368+ offset: 0 ,
369+ } ,
370+ ) ;
371+ }
372+
373+ #[ test]
374+ fn hour_minute_only ( ) {
375+ // 20080214T2030 = Feb 14, 2008 20:30:00 UTC
376+ assert_eq ! (
377+ gix_date:: parse( "20080214T2030" , None ) . unwrap( ) ,
378+ Time {
379+ seconds: 1203021000 ,
380+ offset: 0 ,
381+ } ,
382+ ) ;
383+ }
384+
385+ #[ test]
386+ fn hour_minute_with_colon ( ) {
387+ // 20080214T20:30 = Feb 14, 2008 20:30:00 UTC
388+ assert_eq ! (
389+ gix_date:: parse( "20080214T20:30" , None ) . unwrap( ) ,
390+ Time {
391+ seconds: 1203021000 ,
392+ offset: 0 ,
393+ } ,
394+ ) ;
395+ }
396+
397+ #[ test]
398+ fn hour_only ( ) {
399+ // 20080214T20 = Feb 14, 2008 20:00:00 UTC
400+ assert_eq ! (
401+ gix_date:: parse( "20080214T20" , None ) . unwrap( ) ,
402+ Time {
403+ seconds: 1203019200 ,
404+ offset: 0 ,
405+ } ,
406+ ) ;
407+ }
408+
409+ #[ test]
410+ fn with_timezone ( ) {
411+ // 20080214T203045-04:00 = Feb 14, 2008 20:30:45 -04:00
412+ // UTC seconds = local time + 4 hours = 1203021045 + 14400 = 1203035445
413+ assert_eq ! (
414+ gix_date:: parse( "20080214T203045-04:00" , None ) . unwrap( ) ,
415+ Time {
416+ seconds: 1203035445 ,
417+ offset: -14400 ,
418+ } ,
419+ ) ;
420+ }
421+
422+ #[ test]
423+ fn with_space_before_timezone ( ) {
424+ // 20080214T203045 -04:00 = Feb 14, 2008 20:30:45 -04:00
425+ // UTC seconds = local time + 4 hours = 1203021045 + 14400 = 1203035445
426+ assert_eq ! (
427+ gix_date:: parse( "20080214T203045 -04:00" , None ) . unwrap( ) ,
428+ Time {
429+ seconds: 1203035445 ,
430+ offset: -14400 ,
431+ } ,
432+ ) ;
433+ }
434+
435+ #[ test]
436+ fn with_subseconds_ignored ( ) {
437+ // Subsecond precision is ignored, like Git does
438+ // 20080214T203045.019-04:00 = Feb 14, 2008 20:30:45.019 -04:00
439+ // UTC seconds = local time + 4 hours = 1203021045 + 14400 = 1203035445
440+ assert_eq ! (
441+ gix_date:: parse( "20080214T203045.019-04:00" , None ) . unwrap( ) ,
442+ Time {
443+ seconds: 1203035445 ,
444+ offset: -14400 ,
445+ } ,
446+ ) ;
447+ }
448+
449+ #[ test]
450+ fn with_subseconds_no_timezone ( ) {
451+ // 20080214T000000.20 = Feb 14, 2008 00:00:00.20 UTC
452+ assert_eq ! (
453+ gix_date:: parse( "20080214T000000.20" , None ) . unwrap( ) ,
454+ Time {
455+ seconds: 1202947200 ,
456+ offset: 0 ,
457+ } ,
458+ ) ;
459+ }
460+
461+ #[ test]
462+ fn with_subseconds_colon_time ( ) {
463+ // 20080214T00:00:00.20 = Feb 14, 2008 00:00:00.20 UTC
464+ assert_eq ! (
465+ gix_date:: parse( "20080214T00:00:00.20" , None ) . unwrap( ) ,
466+ Time {
467+ seconds: 1202947200 ,
468+ offset: 0 ,
469+ } ,
470+ ) ;
471+ }
472+ }
473+
474+ /// Tests for ISO8601 with dots format (YYYY.MM.DD HH:MM:SS offset)
475+ mod iso8601_dots {
476+ use gix_date:: Time ;
477+
478+ #[ test]
479+ fn basic ( ) {
480+ // 2008.02.14 20:30:45 -0500
481+ // UTC seconds = local time + 5 hours = 1203021045 + 18000 = 1203039045
482+ assert_eq ! (
483+ gix_date:: parse( "2008.02.14 20:30:45 -0500" , None ) . unwrap( ) ,
484+ Time {
485+ seconds: 1203039045 ,
486+ offset: -18000 ,
487+ } ,
488+ ) ;
489+ }
490+ }
491+
492+ /// Tests for flexible timezone offset formats
493+ mod flexible_offset {
494+ use gix_date:: Time ;
495+
496+ #[ test]
497+ fn z_suffix_for_utc ( ) {
498+ // 1970-01-01 00:00:00 Z = Unix epoch
499+ assert_eq ! (
500+ gix_date:: parse( "1970-01-01 00:00:00 Z" , None ) . unwrap( ) ,
501+ Time { seconds: 0 , offset: 0 } ,
502+ ) ;
503+ }
504+
505+ #[ test]
506+ fn two_digit_hour_offset ( ) {
507+ // 2008-02-14 20:30:45 -05 = 2008-02-14 20:30:45 -0500
508+ // UTC seconds = local time + 5 hours = 1203021045 + 18000 = 1203039045
509+ assert_eq ! (
510+ gix_date:: parse( "2008-02-14 20:30:45 -05" , None ) . unwrap( ) ,
511+ Time {
512+ seconds: 1203039045 ,
513+ offset: -18000 ,
514+ } ,
515+ ) ;
516+ }
517+
518+ #[ test]
519+ fn colon_separated_offset ( ) {
520+ // 2008-02-14 20:30:45 -05:00 = 2008-02-14 20:30:45 -0500
521+ // UTC seconds = local time + 5 hours = 1203021045 + 18000 = 1203039045
522+ assert_eq ! (
523+ gix_date:: parse( "2008-02-14 20:30:45 -05:00" , None ) . unwrap( ) ,
524+ Time {
525+ seconds: 1203039045 ,
526+ offset: -18000 ,
527+ } ,
528+ ) ;
529+ }
530+
531+ #[ test]
532+ fn fifteen_minute_offset ( ) {
533+ // 2008-02-14 20:30:45 -0015
534+ // UTC seconds = local time + 15 min = 1203021045 + 900 = 1203021945
535+ assert_eq ! (
536+ gix_date:: parse( "2008-02-14 20:30:45 -0015" , None ) . unwrap( ) ,
537+ Time {
538+ seconds: 1203021945 ,
539+ offset: -900 ,
540+ } ,
541+ ) ;
542+ }
543+ }
544+
545+ /// Tests for subsecond precision in ISO8601 formats (ignored like Git)
546+ mod subsecond_precision {
547+ use gix_date:: Time ;
548+
549+ #[ test]
550+ fn iso8601_with_subseconds ( ) {
551+ // 2008-02-14 20:30:45.019-04:00 - subseconds ignored
552+ // UTC seconds = local time + 4 hours = 1203021045 + 14400 = 1203035445
553+ assert_eq ! (
554+ gix_date:: parse( "2008-02-14 20:30:45.019-04:00" , None ) . unwrap( ) ,
555+ Time {
556+ seconds: 1203035445 ,
557+ offset: -14400 ,
558+ } ,
559+ ) ;
560+ }
561+ }
562+
342563/// Various cases the fuzzer found
343564mod fuzz {
344565 #[ test]
0 commit comments