1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.time;
18
19 import java.io.Serializable;
20 import java.text.DecimalFormat;
21 import java.util.regex.Matcher;
22 import java.util.regex.Pattern;
23
24 import org.orekit.errors.OrekitIllegalArgumentException;
25 import org.orekit.errors.OrekitMessages;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class DateComponents implements Serializable, Comparable<DateComponents> {
43
44
45
46
47
48
49
50
51 public static final DateComponents JULIAN_EPOCH;
52
53
54 public static final DateComponents MODIFIED_JULIAN_EPOCH;
55
56
57 public static final DateComponents FIFTIES_EPOCH;
58
59
60 public static final DateComponents CCSDS_EPOCH;
61
62
63 public static final DateComponents GALILEO_EPOCH;
64
65
66 public static final DateComponents GPS_EPOCH;
67
68
69 public static final DateComponents QZSS_EPOCH;
70
71
72 public static final DateComponents IRNSS_EPOCH;
73
74
75 public static final DateComponents BEIDOU_EPOCH;
76
77
78 public static final DateComponents GLONASS_EPOCH;
79
80
81 public static final DateComponents J2000_EPOCH;
82
83
84 public static final DateComponents JAVA_EPOCH;
85
86
87
88
89
90
91
92
93 public static final DateComponents MAX_EPOCH;
94
95
96
97
98
99
100
101
102 public static final DateComponents MIN_EPOCH;
103
104
105 private static final long serialVersionUID = -2462694707837970938L;
106
107
108 private static final YearFactory PROLEPTIC_JULIAN_FACTORY = new ProlepticJulianFactory();
109
110
111 private static final YearFactory JULIAN_FACTORY = new JulianFactory();
112
113
114 private static final YearFactory GREGORIAN_FACTORY = new GregorianFactory();
115
116
117 private static final MonthDayFactory LEAP_YEAR_FACTORY = new LeapYearFactory();
118
119
120 private static final MonthDayFactory COMMON_YEAR_FACTORY = new CommonYearFactory();
121
122
123 private static final DecimalFormat FOUR_DIGITS = new DecimalFormat("0000");
124
125
126 private static final DecimalFormat TWO_DIGITS = new DecimalFormat("00");
127
128
129 private static final int MJD_TO_J2000 = 51544;
130
131
132 private static final Pattern CALENDAR_FORMAT = Pattern.compile("^(-?\\d\\d\\d\\d)-?(\\d\\d)-?(\\d\\d)$");
133
134
135 private static final Pattern ORDINAL_FORMAT = Pattern.compile("^(-?\\d\\d\\d\\d)-?(\\d\\d\\d)$");
136
137
138 private static final Pattern WEEK_FORMAT = Pattern.compile("^(-?\\d\\d\\d\\d)-?W(\\d\\d)-?(\\d)$");
139
140 static {
141
142
143 JULIAN_EPOCH = new DateComponents(-4712, 1, 1);
144 MODIFIED_JULIAN_EPOCH = new DateComponents(1858, 11, 17);
145 FIFTIES_EPOCH = new DateComponents(1950, 1, 1);
146 CCSDS_EPOCH = new DateComponents(1958, 1, 1);
147 GALILEO_EPOCH = new DateComponents(1999, 8, 22);
148 GPS_EPOCH = new DateComponents(1980, 1, 6);
149 QZSS_EPOCH = new DateComponents(1980, 1, 6);
150 IRNSS_EPOCH = new DateComponents(1999, 8, 22);
151 BEIDOU_EPOCH = new DateComponents(2006, 1, 1);
152 GLONASS_EPOCH = new DateComponents(1996, 1, 1);
153 J2000_EPOCH = new DateComponents(2000, 1, 1);
154 JAVA_EPOCH = new DateComponents(1970, 1, 1);
155 MAX_EPOCH = new DateComponents(Integer.MAX_VALUE);
156 MIN_EPOCH = new DateComponents(Integer.MIN_VALUE);
157 }
158
159
160 private final int year;
161
162
163 private final int month;
164
165
166 private final int day;
167
168
169
170
171
172
173
174
175
176 public DateComponents(final int year, final int month, final int day)
177 throws IllegalArgumentException {
178
179
180
181 if ((month < 1) || (month > 12)) {
182 throw new OrekitIllegalArgumentException(OrekitMessages.NON_EXISTENT_MONTH, month);
183 }
184
185
186 this.year = year;
187 this.month = month;
188 this.day = day;
189
190
191 final DateComponentsteComponents">DateComponents check = new DateComponents(getJ2000Day());
192
193
194
195 if ((year != check.year) || (month != check.month) || (day != check.day)) {
196 throw new OrekitIllegalArgumentException(OrekitMessages.NON_EXISTENT_YEAR_MONTH_DAY,
197 year, month, day);
198 }
199
200 }
201
202
203
204
205
206
207
208
209
210 public DateComponents(final int year, final Month month, final int day)
211 throws IllegalArgumentException {
212 this(year, month.getNumber(), day);
213 }
214
215
216
217
218
219
220
221 public DateComponents(final int year, final int dayNumber)
222 throws IllegalArgumentException {
223 this(J2000_EPOCH, new DateComponents(year - 1, 12, 31).getJ2000Day() + dayNumber);
224 if (dayNumber != getDayOfYear()) {
225 throw new OrekitIllegalArgumentException(OrekitMessages.NON_EXISTENT_DAY_NUMBER_IN_YEAR,
226 dayNumber, year);
227 }
228 }
229
230
231
232
233
234 public DateComponents(final int offset) {
235
236
237
238
239
240
241 YearFactory yFactory = GREGORIAN_FACTORY;
242 if (offset < -152384) {
243 if (offset > -730122) {
244 yFactory = JULIAN_FACTORY;
245 } else {
246 yFactory = PROLEPTIC_JULIAN_FACTORY;
247 }
248 }
249 year = yFactory.getYear(offset);
250 final int dayInYear = offset - yFactory.getLastJ2000DayOfYear(year - 1);
251
252
253 final MonthDayFactory mdFactory =
254 yFactory.isLeap(year) ? LEAP_YEAR_FACTORY : COMMON_YEAR_FACTORY;
255 month = mdFactory.getMonth(dayInYear);
256 day = mdFactory.getDay(dayInYear, month);
257
258 }
259
260
261
262
263
264
265
266
267
268
269 public DateComponentstml#DateComponents">DateComponents(final DateComponents epoch, final int offset) {
270 this(epoch.getJ2000Day() + offset);
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289 public static DateComponents createFromWeekComponents(final int wYear, final int week, final int dayOfWeek)
290 throws IllegalArgumentException {
291
292 final DateComponentsts">DateComponents firstWeekMonday = new DateComponents(getFirstWeekMonday(wYear));
293 final DateComponentsl#DateComponents">DateComponents d = new DateComponents(firstWeekMonday, 7 * week + dayOfWeek - 8);
294
295
296 if ((week != d.getCalendarWeek()) || (dayOfWeek != d.getDayOfWeek())) {
297 throw new OrekitIllegalArgumentException(OrekitMessages.NON_EXISTENT_WEEK_DATE,
298 wYear, week, dayOfWeek);
299 }
300
301 return d;
302
303 }
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329 public static DateComponents parseDate(final String string) {
330
331
332 final Matcher calendarMatcher = CALENDAR_FORMAT.matcher(string);
333 if (calendarMatcher.matches()) {
334 return new DateComponents(Integer.parseInt(calendarMatcher.group(1)),
335 Integer.parseInt(calendarMatcher.group(2)),
336 Integer.parseInt(calendarMatcher.group(3)));
337 }
338
339
340 final Matcher ordinalMatcher = ORDINAL_FORMAT.matcher(string);
341 if (ordinalMatcher.matches()) {
342 return new DateComponents(Integer.parseInt(ordinalMatcher.group(1)),
343 Integer.parseInt(ordinalMatcher.group(2)));
344 }
345
346
347 final Matcher weekMatcher = WEEK_FORMAT.matcher(string);
348 if (weekMatcher.matches()) {
349 return createFromWeekComponents(Integer.parseInt(weekMatcher.group(1)),
350 Integer.parseInt(weekMatcher.group(2)),
351 Integer.parseInt(weekMatcher.group(3)));
352 }
353
354 throw new OrekitIllegalArgumentException(OrekitMessages.NON_EXISTENT_DATE, string);
355
356 }
357
358
359
360
361 public int getYear() {
362 return year;
363 }
364
365
366
367
368 public int getMonth() {
369 return month;
370 }
371
372
373
374
375 public Month getMonthEnum() {
376 return Month.getMonth(month);
377 }
378
379
380
381
382 public int getDay() {
383 return day;
384 }
385
386
387
388
389 public int getJ2000Day() {
390 YearFactory yFactory = GREGORIAN_FACTORY;
391 if (year < 1583) {
392 if (year < 1) {
393 yFactory = PROLEPTIC_JULIAN_FACTORY;
394 } else if ((year < 1582) || (month < 10) || ((month < 11) && (day < 5))) {
395 yFactory = JULIAN_FACTORY;
396 }
397 }
398 final MonthDayFactory mdFactory =
399 yFactory.isLeap(year) ? LEAP_YEAR_FACTORY : COMMON_YEAR_FACTORY;
400 return yFactory.getLastJ2000DayOfYear(year - 1) +
401 mdFactory.getDayInYear(month, day);
402 }
403
404
405
406
407 public int getMJD() {
408 return MJD_TO_J2000 + getJ2000Day();
409 }
410
411
412
413
414
415
416
417
418
419
420
421
422 public int getCalendarWeek() {
423 final int firstWeekMonday = getFirstWeekMonday(year);
424 int daysSincefirstMonday = getJ2000Day() - firstWeekMonday;
425 if (daysSincefirstMonday < 0) {
426
427 daysSincefirstMonday += firstWeekMonday - getFirstWeekMonday(year - 1);
428 } else if (daysSincefirstMonday > 363) {
429
430
431 final int weekYearLength = getFirstWeekMonday(year + 1) - firstWeekMonday;
432 if (daysSincefirstMonday >= weekYearLength) {
433 daysSincefirstMonday -= weekYearLength;
434 }
435 }
436 return 1 + daysSincefirstMonday / 7;
437 }
438
439
440
441
442
443 private static int getFirstWeekMonday(final int year) {
444 final int yearFirst = new DateComponents(year, 1, 1).getJ2000Day();
445 final int offsetToMonday = 4 - (yearFirst + 2) % 7;
446 return yearFirst + offsetToMonday + ((offsetToMonday > 3) ? -7 : 0);
447 }
448
449
450
451
452
453 public int getDayOfWeek() {
454 final int dow = (getJ2000Day() + 6) % 7;
455 return (dow < 1) ? (dow + 7) : dow;
456 }
457
458
459
460
461
462
463 public int getDayOfYear() {
464 return getJ2000Day() - new DateComponents(year - 1, 12, 31).getJ2000Day();
465 }
466
467
468
469
470 public String toString() {
471 return new StringBuffer().
472 append(FOUR_DIGITS.format(year)).append('-').
473 append(TWO_DIGITS.format(month)).append('-').
474 append(TWO_DIGITS.format(day)).
475 toString();
476 }
477
478
479 public int compareTo(final DateComponents other) {
480 final int j2000Day = getJ2000Day();
481 final int otherJ2000Day = other.getJ2000Day();
482 if (j2000Day < otherJ2000Day) {
483 return -1;
484 } else if (j2000Day > otherJ2000Day) {
485 return 1;
486 }
487 return 0;
488 }
489
490
491 public boolean equals(final Object other) {
492 try {
493 final DateComponentsg/orekit/time/DateComponents.html#DateComponents">DateComponents otherDate = (DateComponents) other;
494 return (otherDate != null) && (year == otherDate.year) &&
495 (month == otherDate.month) && (day == otherDate.day);
496 } catch (ClassCastException cce) {
497 return false;
498 }
499 }
500
501
502 public int hashCode() {
503 return (year << 16) ^ (month << 8) ^ day;
504 }
505
506
507 private interface YearFactory {
508
509
510
511
512
513 int getYear(int j2000Day);
514
515
516
517
518
519 int getLastJ2000DayOfYear(int year);
520
521
522
523
524
525 boolean isLeap(int year);
526
527 }
528
529
530 private static class ProlepticJulianFactory implements YearFactory {
531
532
533 public int getYear(final int j2000Day) {
534 return (int) -((-4l * j2000Day - 2920488l) / 1461l);
535 }
536
537
538 public int getLastJ2000DayOfYear(final int year) {
539 return 365 * year + (year + 1) / 4 - 730123;
540 }
541
542
543 public boolean isLeap(final int year) {
544 return (year % 4) == 0;
545 }
546
547 }
548
549
550 private static class JulianFactory implements YearFactory {
551
552
553 public int getYear(final int j2000Day) {
554 return (int) ((4l * j2000Day + 2921948l) / 1461l);
555 }
556
557
558 public int getLastJ2000DayOfYear(final int year) {
559 return 365 * year + year / 4 - 730122;
560 }
561
562
563 public boolean isLeap(final int year) {
564 return (year % 4) == 0;
565 }
566
567 }
568
569
570 private static class GregorianFactory implements YearFactory {
571
572
573 public int getYear(final int j2000Day) {
574
575
576 int year = (int) ((400l * j2000Day + 292194288l) / 146097l);
577
578
579
580 if (j2000Day <= getLastJ2000DayOfYear(year - 1)) {
581 --year;
582 }
583
584
585 return year;
586
587 }
588
589
590 public int getLastJ2000DayOfYear(final int year) {
591 return 365 * year + year / 4 - year / 100 + year / 400 - 730120;
592 }
593
594
595 public boolean isLeap(final int year) {
596 return ((year % 4) == 0) && (((year % 400) == 0) || ((year % 100) != 0));
597 }
598
599 }
600
601
602 private interface MonthDayFactory {
603
604
605
606
607
608 int getMonth(int dayInYear);
609
610
611
612
613
614
615 int getDay(int dayInYear, int month);
616
617
618
619
620
621
622 int getDayInYear(int month, int day);
623
624 }
625
626
627 private static class LeapYearFactory implements MonthDayFactory {
628
629
630 private static final int[] PREVIOUS_MONTH_END_DAY = {
631 0, 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335
632 };
633
634
635 public int getMonth(final int dayInYear) {
636 return (dayInYear < 32) ? 1 : (10 * dayInYear + 313) / 306;
637 }
638
639
640 public int getDay(final int dayInYear, final int month) {
641 return dayInYear - PREVIOUS_MONTH_END_DAY[month];
642 }
643
644
645 public int getDayInYear(final int month, final int day) {
646 return day + PREVIOUS_MONTH_END_DAY[month];
647 }
648
649 }
650
651
652 private static class CommonYearFactory implements MonthDayFactory {
653
654
655 private static final int[] PREVIOUS_MONTH_END_DAY = {
656 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
657 };
658
659
660 public int getMonth(final int dayInYear) {
661 return (dayInYear < 32) ? 1 : (10 * dayInYear + 323) / 306;
662 }
663
664
665 public int getDay(final int dayInYear, final int month) {
666 return dayInYear - PREVIOUS_MONTH_END_DAY[month];
667 }
668
669
670 public int getDayInYear(final int month, final int day) {
671 return day + PREVIOUS_MONTH_END_DAY[month];
672 }
673
674 }
675
676 }