@@ -162,7 +162,7 @@ struct Timestamp
162162 /+ +
163163 Fraction
164164
165- The `fraction_exponent ` and `fraction_coefficient ` denote the fractional seconds of the timestamp as a decimal value
165+ The `fractionExponent ` and `fractionCoefficient ` denote the fractional seconds of the timestamp as a decimal value
166166 The fractional seconds’ value is `coefficient * 10 ^ exponent`.
167167 It must be greater than or equal to zero and less than 1.
168168 A missing coefficient defaults to zero.
@@ -382,6 +382,53 @@ struct Timestamp
382382 assert (st == cast (SysTime) ts);
383383 }
384384
385+ /+ +
386+ Creates a fake timestamp from a Duration using `total!"hnsecs"` method.
387+ For positive and zero timestamps the format is
388+ `wwww-dd-88Thh:mm:ss.nnnnnnn`
389+ and for negative timestamps
390+ `wwww-dd-99Thh:mm:ss.nnnnnnn`.
391+ +/
392+ this (Duration)(const Duration duration)
393+ if (Duration.stringof == " Duration" )
394+ {
395+ auto hnsecs = duration.total! " hnsecs" ;
396+ ulong abs = hnsecs < 0 ? - hnsecs : hnsecs;
397+ precision = Precision.fraction;
398+ day = hnsecs >= 0 ? 88 : 99 ;
399+ fractionExponent = - 7 ;
400+ fractionCoefficient = abs % 10_000_000U;
401+ abs /= 10_000_000U;
402+ second = abs % 60 ;
403+ abs /= 60 ;
404+ minute = abs % 60 ;
405+ abs /= 60 ;
406+ hour = abs % 24 ;
407+ abs /= 24 ;
408+ month = abs % 7 ;
409+ abs /= 7 ;
410+ year = cast (typeof (year)) abs;
411+ }
412+
413+ // /
414+ version (mir_test)
415+ @safe unittest {
416+ import core.time : Duration, weeks, days, hours, minutes, seconds, hnsecs;
417+
418+ auto duration = 5. weeks + 2. days + 7. hours + 40. minutes + 4. seconds + 9876543. hnsecs;
419+ Timestamp ts = duration;
420+
421+ assert (ts.toISOExtString == ` 0005-02-88T07:40:04.9876543Z` );
422+ assert (duration == cast (Duration) ts);
423+
424+ duration = - duration;
425+ ts = Timestamp(duration);
426+ assert (ts.toISOExtString == ` 0005-02-99T07:40:04.9876543Z` );
427+ assert (duration == cast (Duration) ts);
428+
429+ assert (Timestamp(Duration.zero).toISOExtString == ` 0000-00-88T00:00:00.0000000Z` );
430+ }
431+
385432 /+ +
386433 Decomposes Timestamp to an algebraic type.
387434 Supported types up to T.stringof equivalence:
@@ -414,6 +461,11 @@ struct Timestamp
414461 if (precision == precision.month)
415462 return T (opCast ! AT );
416463
464+ foreach (AT ; T.AllowedTypes)
465+ static if (AT .stringof == " Duration" )
466+ if (isDuration)
467+ return T (opCast ! AT );
468+
417469 foreach (AT ; T.AllowedTypes)
418470 static if (AT .stringof == " YearMonthDay" || AT .stringof == " Date" || AT .stringof == " date" )
419471 if (precision == precision.day)
@@ -494,6 +546,7 @@ struct Timestamp
494546 || T.stringof == " Date"
495547 || T.stringof == " date"
496548 || T.stringof == " TimeOfDay"
549+ || T.stringof == " Duration"
497550 || T.stringof == " DateTime"
498551 || T.stringof == " SysTime" )
499552 {
@@ -523,29 +576,47 @@ struct Timestamp
523576 import std.datetime.date : DateTime ;
524577 import std.datetime.systime : SysTime;
525578 import std.datetime.timezone : UTC , SimpleTimeZone;
526- auto ret = SysTime(DateTime (year, month, day, hour, minute, second), UTC ());
527- if (fractionCoefficient)
528- {
529- long coeff = fractionCoefficient;
530- int exp = fractionExponent;
531- while (exp > - 7 )
532- {
533- exp-- ;
534- coeff *= 10 ;
535- }
536- while (exp < - 7 )
537- {
538- exp++ ;
539- coeff /= 10 ;
540- }
541- ret.fracSecs = coeff.hnsecs;
542- }
579+ auto ret = SysTime(DateTime (year, month, day, hour, minute, second), getPhobosFraction.hnsecs, UTC ());
543580 if (offset)
544581 {
545582 ret = ret.toOtherTZ(new immutable SimpleTimeZone(offset.minutes));
546583 }
547584 return ret;
548585 }
586+ else
587+ static if (T.stringof == " Duration" )
588+ {
589+ if (! isDuration)
590+ throw ExpectedDuration;
591+ auto coeff = ((((long (year) * 7 + month) * 24 + hour) * 60 + minute) * 60 + second) * 10_000_000 + getPhobosFraction;
592+ if (isNegativeDuration)
593+ coeff = - coeff;
594+
595+ import mir.conv: to;
596+ import core.time : hnsecs;
597+ return coeff.hnsecs.to! T;
598+ }
599+ }
600+
601+ private long getPhobosFraction () @property const @safe pure nothrow @nogc
602+ {
603+ long coeff;
604+ if (fractionCoefficient)
605+ {
606+ coeff = fractionCoefficient;
607+ int exp = fractionExponent;
608+ while (exp > - 7 )
609+ {
610+ exp-- ;
611+ coeff *= 10 ;
612+ }
613+ while (exp < - 7 )
614+ {
615+ exp++ ;
616+ coeff /= 10 ;
617+ }
618+ }
619+ return coeff;
549620 }
550621
551622 /+ +
@@ -617,7 +688,7 @@ struct Timestamp
617688 }
618689
619690 /+ +
620- Converts this $(LREF Timestamp) to a string with the format `YYYY-MM-DDThh :mm:ss±hh:mm`.
691+ Converts this $(LREF Timestamp) to a string with the format `yyyy-mm-ddThh :mm:ss[.mmm] ±hh:mm`.
621692
622693 If `w` writer is set, the resulting string will be written directly
623694 to it.
@@ -637,7 +708,7 @@ struct Timestamp
637708 assert (Timestamp(0 , 1 , 5 ).toString == " 0000-01-05" );
638709 assert (Timestamp(- 4 , 1 , 5 ).toString == " -0004-01-05" );
639710
640- // YYYY-MM-DDThh :mm:ss±hh:mm
711+ // yyyy-mm-ddThh :mm:ss[.mmm] ±hh:mm
641712 assert (Timestamp(2021 ).toString == " 2021T" );
642713 assert (Timestamp(2021 , 01 ).toString == " 2021-01T" , Timestamp(2021 , 01 ).toString);
643714 assert (Timestamp(2021 , 01 , 29 ).toString == " 2021-01-29" );
@@ -763,7 +834,7 @@ struct Timestamp
763834 // if (isOutputRange!(W, char))
764835 {
765836 import mir.format: printZeroPad;
766- // YYYY-MM-DDThh :mm:ss±hh:mm
837+ // yyyy-mm-ddThh :mm:ss[.mmm] ±hh:mm
767838 Timestamp t = this ;
768839
769840 if (t.offset)
@@ -956,10 +1027,9 @@ struct Timestamp
9561027 }
9571028
9581029 /+ +
959- Creates a $(LREF Timestamp) from a string with the format `YYYY-MM-DDThh :mm:ss±hh:mm`
1030+ Creates a $(LREF Timestamp) from a string with the format `yyyy-mm-ddThh :mm:ss[.mmm] ±hh:mm`
9601031 or its leading part allowed by the standard.
9611032
962-
9631033 Params:
9641034 str = A string formatted in the way that $(LREF .Timestamp.toISOExtString) formats dates.
9651035 value = (optional) result value.
@@ -1296,4 +1366,16 @@ struct Timestamp
12961366 return true ;
12971367 }
12981368 }
1369+
1370+ // /
1371+ bool isDuration () const @safe pure nothrow @nogc @property
1372+ {
1373+ return day == 88 || day == 99 ;
1374+ }
1375+
1376+ // /
1377+ bool isNegativeDuration () const @safe pure nothrow @nogc @property
1378+ {
1379+ return day == 99 ;
1380+ }
12991381}
0 commit comments