1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.time;
18
19 import org.hipparchus.exception.LocalizedCoreFormats;
20 import org.hipparchus.util.FastMath;
21 import org.orekit.errors.OrekitException;
22 import org.orekit.errors.OrekitMessages;
23
24 import java.io.Serializable;
25 import java.util.concurrent.TimeUnit;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 public class TimeOffset
55 implements Comparable<TimeOffset>, Serializable {
56
57
58 public static final TimeOffset ZERO = new TimeOffset(0L, 0L);
59
60
61 public static final TimeOffset ATTOSECOND = new TimeOffset(0L, 1L);
62
63
64 public static final TimeOffset FEMTOSECOND = new TimeOffset(0L, 1000L);
65
66
67 public static final TimeOffset PICOSECOND = new TimeOffset(0L, 1000000L);
68
69
70 public static final TimeOffset NANOSECOND = new TimeOffset(0L, 1000000000L);
71
72
73 public static final TimeOffset MICROSECOND = new TimeOffset(0L, 1000000000000L);
74
75
76 public static final TimeOffset MILLISECOND = new TimeOffset(0L, 1000000000000000L);
77
78
79 public static final TimeOffset SECOND = new TimeOffset(1L, 0L);
80
81
82 public static final TimeOffset MINUTE = new TimeOffset(60L, 0L);
83
84
85 public static final TimeOffset HOUR = new TimeOffset(3600L, 0L);
86
87
88 public static final TimeOffset DAY = new TimeOffset(86400L, 0L);
89
90
91 public static final TimeOffset DAY_WITH_POSITIVE_LEAP = new TimeOffset(86401L, 0L);
92
93
94
95 public static final TimeOffset NaN = new TimeOffset(Double.NaN);
96
97
98
99 public static final TimeOffset NEGATIVE_INFINITY = new TimeOffset(Double.NEGATIVE_INFINITY);
100
101
102 public static final TimeOffset POSITIVE_INFINITY = new TimeOffset(Double.POSITIVE_INFINITY);
103
104
105 private static final long NAN_INDICATOR = -0XFFL;
106
107
108 private static final long POSITIVE_INFINITY_INDICATOR = -0XFF00L;
109
110
111 private static final long NEGATIVE_INFINITY_INDICATOR = -0XFF0000L;
112
113
114 private static final long MILLIS_IN_SECOND = 1000L;
115
116
117 private static final long MICROS_IN_SECOND = 1000000L;
118
119
120 private static final long NANOS_IN_SECOND = 1000000000L;
121
122
123 private static final long ATTOS_IN_SECOND = 1000000000000000000L;
124
125
126 private static final long ATTOS_IN_HALF_SECOND = 500000000000000000L;
127
128
129
130
131
132
133 private static final long SPLIT = 1000000000L;
134
135
136 private static final int DIGITS_ATTOS = 18;
137
138
139
140 private static final long[] MULTIPLIERS = new long[] {
141 1L,
142 10L,
143 100L,
144 1000L,
145 10000L,
146 100000L,
147 1000000L,
148 10000000L,
149 100000000L,
150 1000000000L,
151 10000000000L,
152 100000000000L,
153 1000000000000L,
154 10000000000000L,
155 100000000000000L,
156 1000000000000000L,
157 10000000000000000L,
158 100000000000000000L,
159 1000000000000000000L
160 };
161
162
163
164 private static final long serialVersionUID = 20240711L;
165
166
167 private final long seconds;
168
169
170 private final long attoSeconds;
171
172
173
174
175
176 public TimeOffset(final TimeOffset... times) {
177 final RunningSum runningSum = new RunningSum();
178 for (final TimeOffset time : times) {
179 runningSum.add(time);
180 }
181 final TimeOffset sum = runningSum.normalize();
182 this.seconds = sum.getSeconds();
183 this.attoSeconds = sum.getAttoSeconds();
184 }
185
186
187
188
189
190
191
192
193
194
195 public TimeOffset(final long seconds, final long attoSeconds) {
196 final long qAtto = attoSeconds / ATTOS_IN_SECOND;
197 final long rAtto = attoSeconds - qAtto * ATTOS_IN_SECOND;
198 if (rAtto < 0L) {
199 this.seconds = seconds + qAtto - 1L;
200 this.attoSeconds = ATTOS_IN_SECOND + rAtto;
201 } else {
202 this.seconds = seconds + qAtto;
203 this.attoSeconds = rAtto;
204 }
205 }
206
207
208
209
210
211
212 public TimeOffset(final double time) {
213 if (Double.isNaN(time)) {
214 seconds = 0L;
215 attoSeconds = NAN_INDICATOR;
216 } else if (time < Long.MIN_VALUE || time > Long.MAX_VALUE) {
217 if (time < 0L) {
218 seconds = Long.MIN_VALUE;
219 attoSeconds = NEGATIVE_INFINITY_INDICATOR;
220 } else {
221 seconds = Long.MAX_VALUE;
222 attoSeconds = POSITIVE_INFINITY_INDICATOR;
223 }
224 } else {
225 final double tiSeconds = FastMath.rint(time);
226 final double subSeconds = time - tiSeconds;
227 if (subSeconds < 0L) {
228 seconds = (long) tiSeconds - 1L;
229 attoSeconds = FastMath.round(subSeconds * ATTOS_IN_SECOND) + ATTOS_IN_SECOND;
230 } else {
231 seconds = (long) tiSeconds;
232 attoSeconds = FastMath.round(subSeconds * ATTOS_IN_SECOND);
233 }
234 }
235 }
236
237
238
239
240
241
242
243
244
245 public TimeOffset(final long factor, final TimeOffset time) {
246 this(factor < 0 ? time.multiply(-factor).negate() : time.multiply(factor));
247 }
248
249
250
251
252
253
254
255
256
257
258
259
260 public TimeOffset(final long f1, final TimeOffset t1,
261 final long f2, final TimeOffset t2) {
262 this(new TimeOffset(f1, t1).add(new TimeOffset(f2, t2)));
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 public TimeOffset(final long f1, final TimeOffset t1,
279 final long f2, final TimeOffset t2,
280 final long f3, final TimeOffset t3) {
281 this(new TimeOffset(f1, t1).add(new TimeOffset(f2, t2)).add(new TimeOffset(f3, t3)));
282 }
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public TimeOffset(final long f1, final TimeOffset t1,
300 final long f2, final TimeOffset t2,
301 final long f3, final TimeOffset t3,
302 final long f4, final TimeOffset t4) {
303 this(new TimeOffset(f1, t1).
304 add(new TimeOffset(f2, t2)).
305 add(new TimeOffset(f3, t3)).
306 add(new TimeOffset(f4, t4)));
307 }
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326 public TimeOffset(final long f1, final TimeOffset t1,
327 final long f2, final TimeOffset t2,
328 final long f3, final TimeOffset t3,
329 final long f4, final TimeOffset t4,
330 final long f5, final TimeOffset t5) {
331 this(new TimeOffset(f1, t1).
332 add(new TimeOffset(f2, t2)).
333 add(new TimeOffset(f3, t3)).
334 add(new TimeOffset(f4, t4)).
335 add(new TimeOffset(f5, t5)));
336 }
337
338
339
340
341
342
343
344 public TimeOffset(final long time, final TimeUnit unit) {
345 switch (unit) {
346 case DAYS: {
347 final long limit = (Long.MAX_VALUE - DAY.seconds / 2) / DAY.seconds;
348 if (time < -limit) {
349 seconds = Long.MIN_VALUE;
350 attoSeconds = NEGATIVE_INFINITY_INDICATOR;
351 } else if (time > limit) {
352 seconds = Long.MAX_VALUE;
353 attoSeconds = POSITIVE_INFINITY_INDICATOR;
354 } else {
355 seconds = time * DAY.seconds;
356 attoSeconds = 0L;
357 }
358 break;
359 }
360 case HOURS: {
361 final long limit = (Long.MAX_VALUE - HOUR.seconds / 2) / HOUR.seconds;
362 if (time < -limit) {
363 seconds = Long.MIN_VALUE;
364 attoSeconds = NEGATIVE_INFINITY_INDICATOR;
365 } else if (time > limit) {
366 seconds = Long.MAX_VALUE;
367 attoSeconds = POSITIVE_INFINITY_INDICATOR;
368 } else {
369 seconds = time * HOUR.seconds;
370 attoSeconds = 0L;
371 }
372 break;
373 }
374 case MINUTES: {
375 final long limit = (Long.MAX_VALUE - MINUTE.seconds / 2) / MINUTE.seconds;
376 if (time < -limit) {
377 seconds = Long.MIN_VALUE;
378 attoSeconds = NEGATIVE_INFINITY_INDICATOR;
379 } else if (time > limit) {
380 seconds = Long.MAX_VALUE;
381 attoSeconds = POSITIVE_INFINITY_INDICATOR;
382 } else {
383 seconds = time * MINUTE.seconds;
384 attoSeconds = 0L;
385 }
386 break;
387 }
388 case SECONDS:
389 seconds = time;
390 attoSeconds = 0L;
391 break;
392 case MILLISECONDS: {
393 final long s = time / MILLIS_IN_SECOND;
394 final long r = (time - s * MILLIS_IN_SECOND) * MILLISECOND.attoSeconds;
395 if (r < 0L) {
396 seconds = s - 1L;
397 attoSeconds = ATTOS_IN_SECOND + r;
398 } else {
399 seconds = s;
400 attoSeconds = r;
401 }
402 break;
403 }
404 case MICROSECONDS: {
405 final long s = time / MICROS_IN_SECOND;
406 final long r = (time - s * MICROS_IN_SECOND) * MICROSECOND.attoSeconds;
407 if (r < 0L) {
408 seconds = s - 1L;
409 attoSeconds = ATTOS_IN_SECOND + r;
410 } else {
411 seconds = s;
412 attoSeconds = r;
413 }
414 break;
415 }
416 case NANOSECONDS: {
417 final long s = time / NANOS_IN_SECOND;
418 final long r = (time - s * NANOS_IN_SECOND) * NANOSECOND.attoSeconds;
419 if (r < 0L) {
420 seconds = s - 1L;
421 attoSeconds = ATTOS_IN_SECOND + r;
422 } else {
423 seconds = s;
424 attoSeconds = r;
425 }
426 break;
427 }
428 default:
429 throw new OrekitException(OrekitMessages.UNKNOWN_UNIT, unit.name());
430 }
431 }
432
433
434
435
436 private TimeOffset(final TimeOffset time) {
437 seconds = time.seconds;
438 attoSeconds = time.attoSeconds;
439 }
440
441
442
443
444 public boolean isZero() {
445 return seconds == 0L && attoSeconds == 0L;
446 }
447
448
449
450
451
452
453
454
455 public boolean isFinite() {
456 return attoSeconds >= 0L;
457 }
458
459
460
461
462
463
464
465
466 public boolean isNaN() {
467 return attoSeconds == NAN_INDICATOR;
468 }
469
470
471
472
473
474
475
476
477 public boolean isInfinite() {
478 return isPositiveInfinity() || isNegativeInfinity();
479 }
480
481
482
483
484
485
486
487
488 public boolean isPositiveInfinity() {
489 return attoSeconds == POSITIVE_INFINITY_INDICATOR;
490 }
491
492
493
494
495
496
497
498
499 public boolean isNegativeInfinity() {
500 return attoSeconds == NEGATIVE_INFINITY_INDICATOR;
501 }
502
503
504
505
506
507 public TimeOffset add(final TimeOffset t) {
508 final RunningSum runningSum = new RunningSum();
509 runningSum.add(this);
510 runningSum.add(t);
511 return runningSum.normalize();
512 }
513
514
515
516
517
518 public TimeOffset subtract(final TimeOffset t) {
519 if (attoSeconds < 0 || t.attoSeconds < 0) {
520
521 if (isNaN() ||
522 t.isNaN() ||
523 isPositiveInfinity() && t.isPositiveInfinity() ||
524 isNegativeInfinity() && t.isNegativeInfinity()) {
525 return NaN;
526 } else if (isInfinite()) {
527
528 return this;
529 } else {
530
531 return t.isPositiveInfinity() ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
532 }
533 } else {
534
535 return new TimeOffset(seconds - t.seconds, attoSeconds - t.attoSeconds);
536 }
537 }
538
539
540
541
542
543 public TimeOffset multiply(final long p) {
544 if (p < 0) {
545 throw new OrekitException(OrekitMessages.NOT_POSITIVE, p);
546 }
547 if (isFinite()) {
548 final TimeOffset abs = seconds < 0 ? negate() : this;
549 final long pHigh = p / SPLIT;
550 final long pLow = p - pHigh * SPLIT;
551 final long sHigh = abs.seconds / SPLIT;
552 final long sLow = abs.seconds - sHigh * SPLIT;
553 final long aHigh = abs.attoSeconds / SPLIT;
554 final long aLow = abs.attoSeconds - aHigh * SPLIT;
555 final long ps1 = pHigh * sLow + pLow * sHigh;
556 final long ps0 = pLow * sLow;
557 final long pa2 = pHigh * aHigh;
558 final long pa1 = pHigh * aLow + pLow * aHigh;
559 final long pa1High = pa1 / SPLIT;
560 final long pa1Low = pa1 - pa1High * SPLIT;
561 final long pa0 = pLow * aLow;
562
563
564 if (pHigh * sHigh != 0 || ps1 / SPLIT != 0) {
565 throw new OrekitException(LocalizedCoreFormats.OVERFLOW_IN_MULTIPLICATION, abs.seconds, p);
566 }
567
568
569 final TimeOffset mul = new TimeOffset(SPLIT * ps1 + ps0 + pa2 + pa1High, SPLIT * pa1Low + pa0);
570 return seconds < 0 ? mul.negate() : mul;
571 } else {
572
573 return p == 0 ? TimeOffset.NaN : this;
574 }
575 }
576
577
578
579
580
581 public TimeOffset divide(final int q) {
582 if (q <= 0) {
583 throw new OrekitException(OrekitMessages.NOT_STRICTLY_POSITIVE, q);
584 }
585 if (isFinite()) {
586 final long sSec = seconds / q;
587 final long rSec = seconds - sSec * q;
588 final long sK = ATTOS_IN_SECOND / q;
589 final long rK = ATTOS_IN_SECOND - sK * q;
590 final TimeOffset tsSec = new TimeOffset(0L, sSec);
591 final TimeOffset trSec = new TimeOffset(0L, rSec);
592 return new TimeOffset(tsSec.multiply(sK).multiply(q),
593 tsSec.multiply(rK),
594 trSec.multiply(sK),
595
596
597 new TimeOffset(0L, (attoSeconds + rSec * rK) / q));
598 } else {
599
600 return this;
601 }
602 }
603
604
605
606
607 public TimeOffset negate() {
608
609 if (attoSeconds < 0) {
610
611 return isNaN() ? this : (seconds < 0 ? POSITIVE_INFINITY : NEGATIVE_INFINITY);
612 } else {
613
614 return new TimeOffset(-seconds, -attoSeconds);
615 }
616 }
617
618
619
620
621
622
623 public long getRoundedTime(final TimeUnit unit) {
624
625
626 if (attoSeconds < 0) {
627
628 return (isNaN() || seconds >= 0) ? Long.MAX_VALUE : Long.MIN_VALUE;
629 }
630
631 final long sign = seconds < 0L ? -1L : 1L;
632 switch (unit) {
633 case DAYS:
634 return sign * ((sign * seconds + DAY.seconds / 2) / DAY.seconds);
635 case HOURS:
636 return sign * ((sign * seconds + HOUR.seconds / 2) / HOUR.seconds);
637 case MINUTES:
638 return sign * ((sign * seconds + MINUTE.seconds / 2) / MINUTE.seconds);
639 case SECONDS:
640 return seconds + ((attoSeconds >= ATTOS_IN_SECOND / 2) ? 1 : 0);
641 case MILLISECONDS:
642 return seconds * MILLIS_IN_SECOND +
643 (attoSeconds + MILLISECOND.attoSeconds / 2) / MILLISECOND.attoSeconds;
644 case MICROSECONDS:
645 return seconds * MICROS_IN_SECOND +
646 (attoSeconds + MICROSECOND.attoSeconds / 2) / MICROSECOND.attoSeconds;
647 case NANOSECONDS:
648 return seconds * NANOS_IN_SECOND +
649 (attoSeconds + NANOSECOND.attoSeconds / 2) / NANOSECOND.attoSeconds;
650 default:
651 throw new OrekitException(OrekitMessages.UNKNOWN_UNIT, unit.name());
652 }
653 }
654
655
656
657
658 public long getSeconds() {
659 return seconds;
660 }
661
662
663
664
665
666
667
668
669
670
671
672 public long getAttoSeconds() {
673 return attoSeconds;
674 }
675
676
677
678
679
680
681
682
683 public double toDouble() {
684 if (isFinite()) {
685
686 long closeSeconds = seconds;
687 long signedAttoSeconds = attoSeconds;
688 if (attoSeconds > ATTOS_IN_HALF_SECOND) {
689
690
691
692 closeSeconds++;
693 signedAttoSeconds -= ATTOS_IN_SECOND;
694 }
695 return closeSeconds + ((double) signedAttoSeconds) / ATTOS_IN_SECOND;
696 } else {
697
698 return isNaN() ? Double.NaN : FastMath.copySign(Double.POSITIVE_INFINITY, seconds);
699 }
700 }
701
702
703
704
705
706
707
708
709
710
711
712 public static TimeOffset parse(final String s) {
713
714
715
716
717
718 final int length = s.length();
719 long significandSign = 1L;
720 int exponentSign = 1;
721 int separatorIndex = length;
722 int exponentIndex = length;
723 long beforeSeparator = 0L;
724 long afterSeparator = 0L;
725 int exponent = 0;
726 int digitsBefore = 0;
727 int digitsAfter = 0;
728 int digitsExponent = 0;
729 int index = 0;
730 while (index < length) {
731
732
733 final char c = s.charAt(index);
734
735 if (Character.isDigit(c)) {
736 if (separatorIndex == length) {
737
738 ++digitsBefore;
739 beforeSeparator = beforeSeparator * 10 + c - '0';
740 if (digitsBefore > 19 || beforeSeparator < 0) {
741
742 break;
743 }
744 } else if (exponentIndex == length) {
745
746 if (digitsAfter < DIGITS_ATTOS) {
747
748 afterSeparator = afterSeparator * 10 + c - '0';
749 ++digitsAfter;
750 }
751 } else {
752
753 ++digitsExponent;
754 exponent = exponent * 10 + c - '0';
755 if (digitsExponent > 10 || exponent < 0) {
756
757 break;
758 }
759 }
760 } else if (c == '.' && separatorIndex == length) {
761 separatorIndex = index;
762 } else if ((c == 'e' || c == 'E') && exponentIndex == length) {
763 if (separatorIndex == length) {
764 separatorIndex = index;
765 }
766 exponentIndex = index;
767 } else if (c == '-') {
768 if (index == 0) {
769 significandSign = -1L;
770 } else if (index == exponentIndex + 1) {
771 exponentSign = -1;
772 } else {
773 break;
774 }
775 } else if (c == '+') {
776 if (index == 0) {
777 significandSign = 1L;
778 } else if (index == exponentIndex + 1) {
779 exponentSign = 1;
780 } else {
781 break;
782 }
783 } else {
784 break;
785 }
786
787 ++index;
788
789 }
790
791 if (length == 0 || index < length) {
792
793 if (s.equals("-∞")) {
794 return TimeOffset.NEGATIVE_INFINITY;
795 } else if (s.equals("+∞")) {
796 return TimeOffset.POSITIVE_INFINITY;
797 } else if (s.equalsIgnoreCase("NaN")) {
798 return TimeOffset.NaN;
799 } else {
800 throw new OrekitException(OrekitMessages.CANNOT_PARSE_DATA, s);
801 }
802 }
803
804
805 long seconds;
806 long attoseconds;
807 if (exponentSign < 0) {
808
809 if (exponent >= MULTIPLIERS.length) {
810 seconds = 0L;
811 if (exponent - DIGITS_ATTOS >= MULTIPLIERS.length) {
812
813 attoseconds = 0L;
814 } else {
815 attoseconds = beforeSeparator / MULTIPLIERS[exponent - DIGITS_ATTOS];
816 }
817 } else {
818 final long secondsMultiplier = MULTIPLIERS[exponent];
819 final long attoBeforeMultiplier = MULTIPLIERS[DIGITS_ATTOS - exponent];
820 seconds = beforeSeparator / secondsMultiplier;
821 attoseconds = (beforeSeparator - seconds * secondsMultiplier) * attoBeforeMultiplier;
822 while (digitsAfter + exponent > DIGITS_ATTOS) {
823
824 afterSeparator /= 10;
825 digitsAfter--;
826 }
827 final long attoAfterMultiplier = MULTIPLIERS[DIGITS_ATTOS - exponent - digitsAfter];
828 attoseconds += afterSeparator * attoAfterMultiplier;
829 }
830 } else {
831
832 if (exponent >= MULTIPLIERS.length) {
833 if (beforeSeparator == 0L && afterSeparator == 0L) {
834 return TimeOffset.ZERO;
835 } else if (significandSign < 0) {
836 return TimeOffset.NEGATIVE_INFINITY;
837 } else {
838 return TimeOffset.POSITIVE_INFINITY;
839 }
840 } else {
841 final long secondsMultiplier = MULTIPLIERS[exponent];
842 seconds = beforeSeparator * secondsMultiplier;
843 if (exponent > digitsAfter) {
844 seconds += afterSeparator * MULTIPLIERS[exponent - digitsAfter];
845 attoseconds = 0L;
846 } else {
847 final long q = afterSeparator / MULTIPLIERS[digitsAfter - exponent];
848 seconds += q;
849 attoseconds = (afterSeparator - q * MULTIPLIERS[digitsAfter - exponent]) *
850 MULTIPLIERS[DIGITS_ATTOS - digitsAfter + exponent];
851 }
852 }
853 }
854
855 return new TimeOffset(significandSign * seconds, significandSign * attoseconds);
856
857 }
858
859
860
861
862
863
864
865
866
867
868
869 public int compareTo(final TimeOffset other) {
870 if (isFinite()) {
871 if (other.isFinite()) {
872 return seconds == other.seconds ?
873 Long.compare(attoSeconds, other.attoSeconds) :
874 Long.compare(seconds, other.seconds);
875 } else {
876
877 return other.isNegativeInfinity() ? 1 : -1;
878 }
879 } else {
880
881 if (isNaN()) {
882
883 return other.isNaN() ? 0 : 1;
884 } else if (other.isNaN()) {
885 return -1;
886 } else {
887
888
889 return Long.compare(seconds, other.seconds);
890 }
891 }
892 }
893
894
895 @Override
896 public boolean equals(final Object o) {
897 if (this == o) {
898 return true;
899 }
900 if (o == null || o.getClass() != this.getClass()) {
901 return false;
902 }
903 final TimeOffset timeOffset = (TimeOffset) o;
904 return seconds == timeOffset.seconds && attoSeconds == timeOffset.attoSeconds;
905 }
906
907
908 @Override
909 public int hashCode() {
910 return Long.hashCode(seconds) ^ Long.hashCode(attoSeconds);
911 }
912
913
914 private static class RunningSum {
915
916
917 private static final int COUNT_DOWN_MAX = 9;
918
919
920 private long seconds;
921
922
923 private long attoSeconds;
924
925
926 private boolean addedNaN;
927
928
929 private boolean addedPositiveInfinity;
930
931
932 private boolean addedNegativeInfinity;
933
934
935 private int countDown;
936
937
938
939 RunningSum() {
940 countDown = COUNT_DOWN_MAX;
941 }
942
943
944
945
946 public void add(final TimeOffset term) {
947 if (term.isFinite()) {
948
949 seconds += term.seconds;
950 attoSeconds += term.attoSeconds;
951 if (--countDown == 0) {
952
953
954 normalize();
955 }
956 } else if (term.isNegativeInfinity()) {
957 addedNegativeInfinity = true;
958 } else if (term.isPositiveInfinity()) {
959 addedPositiveInfinity = true;
960 } else {
961 addedNaN = true;
962 }
963 }
964
965
966
967
968 public TimeOffset normalize() {
969
970
971 countDown = COUNT_DOWN_MAX - 1;
972
973 if (addedNaN || addedNegativeInfinity && addedPositiveInfinity) {
974
975 seconds = NaN.seconds;
976 attoSeconds = NaN.attoSeconds;
977 return NaN;
978 } else if (addedNegativeInfinity) {
979
980 seconds = NEGATIVE_INFINITY.seconds;
981 attoSeconds = NEGATIVE_INFINITY.attoSeconds;
982 return NEGATIVE_INFINITY;
983 } else if (addedPositiveInfinity) {
984
985 seconds = POSITIVE_INFINITY.seconds;
986 attoSeconds = POSITIVE_INFINITY.attoSeconds;
987 return POSITIVE_INFINITY;
988 } else {
989
990 final TimeOffset regular = new TimeOffset(seconds, attoSeconds);
991 seconds = regular.seconds;
992 attoSeconds = regular.attoSeconds;
993 return regular;
994 }
995 }
996
997 }
998
999 }