927 * resolve method on the field. By contrast, the {@code ChronoField} class |
877 * resolve method on the field. By contrast, the {@code ChronoField} class |
928 * defines fields that only have meaning relative to the chronology. |
878 * defines fields that only have meaning relative to the chronology. |
929 * As such, {@code ChronoField} date fields are resolved here in the |
879 * As such, {@code ChronoField} date fields are resolved here in the |
930 * context of a specific chronology. |
880 * context of a specific chronology. |
931 * <p> |
881 * <p> |
|
882 * {@code ChronoField} instances are resolved by this method, which may |
|
883 * be overridden in subclasses. |
|
884 * <ul> |
|
885 * <li>{@code EPOCH_DAY} - If present, this is converted to a date and |
|
886 * all other date fields are then cross-checked against the date. |
|
887 * <li>{@code PROLEPTIC_MONTH} - If present, then it is split into the |
|
888 * {@code YEAR} and {@code MONTH_OF_YEAR}. If the mode is strict or smart |
|
889 * then the field is validated. |
|
890 * <li>{@code YEAR_OF_ERA} and {@code ERA} - If both are present, then they |
|
891 * are combined to form a {@code YEAR}. In lenient mode, the {@code YEAR_OF_ERA} |
|
892 * range is not validated, in smart and strict mode it is. The {@code ERA} is |
|
893 * validated for range in all three modes. If only the {@code YEAR_OF_ERA} is |
|
894 * present, and the mode is smart or lenient, then the last available era |
|
895 * is assumed. In strict mode, no era is assumed and the {@code YEAR_OF_ERA} is |
|
896 * left untouched. If only the {@code ERA} is present, then it is left untouched. |
|
897 * <li>{@code YEAR}, {@code MONTH_OF_YEAR} and {@code DAY_OF_MONTH} - |
|
898 * If all three are present, then they are combined to form a date. |
|
899 * In all three modes, the {@code YEAR} is validated. |
|
900 * If the mode is smart or strict, then the month and day are validated. |
|
901 * If the mode is lenient, then the date is combined in a manner equivalent to |
|
902 * creating a date on the first day of the first month in the requested year, |
|
903 * then adding the difference in months, then the difference in days. |
|
904 * If the mode is smart, and the day-of-month is greater than the maximum for |
|
905 * the year-month, then the day-of-month is adjusted to the last day-of-month. |
|
906 * If the mode is strict, then the three fields must form a valid date. |
|
907 * <li>{@code YEAR} and {@code DAY_OF_YEAR} - |
|
908 * If both are present, then they are combined to form a date. |
|
909 * In all three modes, the {@code YEAR} is validated. |
|
910 * If the mode is lenient, then the date is combined in a manner equivalent to |
|
911 * creating a date on the first day of the requested year, then adding |
|
912 * the difference in days. |
|
913 * If the mode is smart or strict, then the two fields must form a valid date. |
|
914 * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and |
|
915 * {@code ALIGNED_DAY_OF_WEEK_IN_MONTH} - |
|
916 * If all four are present, then they are combined to form a date. |
|
917 * In all three modes, the {@code YEAR} is validated. |
|
918 * If the mode is lenient, then the date is combined in a manner equivalent to |
|
919 * creating a date on the first day of the first month in the requested year, then adding |
|
920 * the difference in months, then the difference in weeks, then in days. |
|
921 * If the mode is smart or strict, then the all four fields are validated to |
|
922 * their outer ranges. The date is then combined in a manner equivalent to |
|
923 * creating a date on the first day of the requested year and month, then adding |
|
924 * the amount in weeks and days to reach their values. If the mode is strict, |
|
925 * the date is additionally validated to check that the day and week adjustment |
|
926 * did not change the month. |
|
927 * <li>{@code YEAR}, {@code MONTH_OF_YEAR}, {@code ALIGNED_WEEK_OF_MONTH} and |
|
928 * {@code DAY_OF_WEEK} - If all four are present, then they are combined to |
|
929 * form a date. The approach is the same as described above for |
|
930 * years, months and weeks in {@code ALIGNED_DAY_OF_WEEK_IN_MONTH}. |
|
931 * The day-of-week is adjusted as the next or same matching day-of-week once |
|
932 * the years, months and weeks have been handled. |
|
933 * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code ALIGNED_DAY_OF_WEEK_IN_YEAR} - |
|
934 * If all three are present, then they are combined to form a date. |
|
935 * In all three modes, the {@code YEAR} is validated. |
|
936 * If the mode is lenient, then the date is combined in a manner equivalent to |
|
937 * creating a date on the first day of the requested year, then adding |
|
938 * the difference in weeks, then in days. |
|
939 * If the mode is smart or strict, then the all three fields are validated to |
|
940 * their outer ranges. The date is then combined in a manner equivalent to |
|
941 * creating a date on the first day of the requested year, then adding |
|
942 * the amount in weeks and days to reach their values. If the mode is strict, |
|
943 * the date is additionally validated to check that the day and week adjustment |
|
944 * did not change the year. |
|
945 * <li>{@code YEAR}, {@code ALIGNED_WEEK_OF_YEAR} and {@code DAY_OF_WEEK} - |
|
946 * If all three are present, then they are combined to form a date. |
|
947 * The approach is the same as described above for years and weeks in |
|
948 * {@code ALIGNED_DAY_OF_WEEK_IN_YEAR}. The day-of-week is adjusted as the |
|
949 * next or same matching day-of-week once the years and weeks have been handled. |
|
950 * </ul> |
|
951 * <p> |
932 * The default implementation is suitable for most calendar systems. |
952 * The default implementation is suitable for most calendar systems. |
933 * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA} |
953 * If {@link ChronoField#YEAR_OF_ERA} is found without an {@link ChronoField#ERA} |
934 * then the last era in {@link #eras()} is used. |
954 * then the last era in {@link #eras()} is used. |
935 * The implementation assumes a 7 day week, that the first day-of-month |
955 * The implementation assumes a 7 day week, that the first day-of-month |
936 * has the value 1, and that first day-of-year has the value 1. |
956 * has the value 1, that first day-of-year has the value 1, and that the |
|
957 * first of the month and year always exists. |
937 * |
958 * |
938 * @param fieldValues the map of fields to values, which can be updated, not null |
959 * @param fieldValues the map of fields to values, which can be updated, not null |
939 * @param resolverStyle the requested type of resolve, not null |
960 * @param resolverStyle the requested type of resolve, not null |
940 * @return the resolved date, null if insufficient information to create a date |
961 * @return the resolved date, null if insufficient information to create a date |
941 * @throws DateTimeException if the date cannot be resolved, typically |
962 * @throws DateTimeException if the date cannot be resolved, typically |
942 * because of a conflict in the input data |
963 * because of a conflict in the input data |
943 */ |
964 */ |
944 public ChronoLocalDate<?> resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
965 public ChronoLocalDate resolveDate(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
945 // check epoch-day before inventing era |
966 // check epoch-day before inventing era |
946 if (fieldValues.containsKey(EPOCH_DAY)) { |
967 if (fieldValues.containsKey(EPOCH_DAY)) { |
947 return dateEpochDay(fieldValues.remove(EPOCH_DAY)); |
968 return dateEpochDay(fieldValues.remove(EPOCH_DAY)); |
948 } |
969 } |
949 |
970 |
950 // fix proleptic month before inventing era |
971 // fix proleptic month before inventing era |
951 Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); |
972 resolveProlepticMonth(fieldValues, resolverStyle); |
952 if (pMonth != null) { |
|
953 // first day-of-month is likely to be safest for setting proleptic-month |
|
954 // cannot add to year zero, as not all chronologies have a year zero |
|
955 ChronoLocalDate<?> chronoDate = dateNow() |
|
956 .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); |
|
957 addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); |
|
958 addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); |
|
959 } |
|
960 |
973 |
961 // invent era if necessary to resolve year-of-era |
974 // invent era if necessary to resolve year-of-era |
962 Long yoeLong = fieldValues.remove(YEAR_OF_ERA); |
975 ChronoLocalDate resolved = resolveYearOfEra(fieldValues, resolverStyle); |
963 if (yoeLong != null) { |
976 if (resolved != null) { |
964 Long eraLong = fieldValues.remove(ERA); |
977 return resolved; |
965 int yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); |
|
966 if (eraLong != null) { |
|
967 Era eraObj = eraOf(Math.toIntExact(eraLong)); |
|
968 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); |
|
969 } else if (fieldValues.containsKey(YEAR)) { |
|
970 int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); |
|
971 ChronoLocalDate<?> chronoDate = dateYearDay(year, 1); |
|
972 addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); |
|
973 } else { |
|
974 List<Era> eras = eras(); |
|
975 if (eras.isEmpty()) { |
|
976 addFieldValue(fieldValues, YEAR, yoe); |
|
977 } else { |
|
978 Era eraObj = eras.get(eras.size() - 1); |
|
979 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); |
|
980 } |
|
981 } |
|
982 } |
978 } |
983 |
979 |
984 // build date |
980 // build date |
985 if (fieldValues.containsKey(YEAR)) { |
981 if (fieldValues.containsKey(YEAR)) { |
986 if (fieldValues.containsKey(MONTH_OF_YEAR)) { |
982 if (fieldValues.containsKey(MONTH_OF_YEAR)) { |
987 if (fieldValues.containsKey(DAY_OF_MONTH)) { |
983 if (fieldValues.containsKey(DAY_OF_MONTH)) { |
988 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
984 return resolveYMD(fieldValues, resolverStyle); |
989 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
990 int dom = range(DAY_OF_MONTH).checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); |
|
991 return date(y, moy, dom); |
|
992 } |
985 } |
993 if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { |
986 if (fieldValues.containsKey(ALIGNED_WEEK_OF_MONTH)) { |
994 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { |
987 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_MONTH)) { |
995 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
988 return resolveYMAA(fieldValues, resolverStyle); |
996 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
997 int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); |
|
998 int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); |
|
999 ChronoLocalDate<?> chronoDate = date(y, moy, 1); |
|
1000 return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); |
|
1001 } |
989 } |
1002 if (fieldValues.containsKey(DAY_OF_WEEK)) { |
990 if (fieldValues.containsKey(DAY_OF_WEEK)) { |
1003 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
991 return resolveYMAD(fieldValues, resolverStyle); |
1004 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
1005 int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); |
|
1006 int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); |
|
1007 ChronoLocalDate<?> chronoDate = date(y, moy, 1); |
|
1008 return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); |
|
1009 } |
992 } |
1010 } |
993 } |
1011 } |
994 } |
1012 if (fieldValues.containsKey(DAY_OF_YEAR)) { |
995 if (fieldValues.containsKey(DAY_OF_YEAR)) { |
1013 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
996 return resolveYD(fieldValues, resolverStyle); |
1014 int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); |
|
1015 return dateYearDay(y, doy); |
|
1016 } |
997 } |
1017 if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { |
998 if (fieldValues.containsKey(ALIGNED_WEEK_OF_YEAR)) { |
1018 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { |
999 if (fieldValues.containsKey(ALIGNED_DAY_OF_WEEK_IN_YEAR)) { |
1019 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
1000 return resolveYAA(fieldValues, resolverStyle); |
1020 int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); |
|
1021 int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); |
|
1022 ChronoLocalDate<?> chronoDate = dateYearDay(y, 1); |
|
1023 return chronoDate.plus((aw - 1) * 7 + (ad - 1), ChronoUnit.DAYS); |
|
1024 } |
1001 } |
1025 if (fieldValues.containsKey(DAY_OF_WEEK)) { |
1002 if (fieldValues.containsKey(DAY_OF_WEEK)) { |
1026 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
1003 return resolveYAD(fieldValues, resolverStyle); |
1027 int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); |
|
1028 int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); |
|
1029 ChronoLocalDate<?> chronoDate = dateYearDay(y, 1); |
|
1030 return chronoDate.plus((aw - 1) * 7, ChronoUnit.DAYS).with(nextOrSame(DayOfWeek.of(dow))); |
|
1031 } |
1004 } |
1032 } |
1005 } |
1033 } |
1006 } |
1034 return null; |
1007 return null; |
|
1008 } |
|
1009 |
|
1010 void resolveProlepticMonth(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1011 Long pMonth = fieldValues.remove(PROLEPTIC_MONTH); |
|
1012 if (pMonth != null) { |
|
1013 if (resolverStyle != ResolverStyle.LENIENT) { |
|
1014 PROLEPTIC_MONTH.checkValidValue(pMonth); |
|
1015 } |
|
1016 // first day-of-month is likely to be safest for setting proleptic-month |
|
1017 // cannot add to year zero, as not all chronologies have a year zero |
|
1018 ChronoLocalDate chronoDate = dateNow() |
|
1019 .with(DAY_OF_MONTH, 1).with(PROLEPTIC_MONTH, pMonth); |
|
1020 addFieldValue(fieldValues, MONTH_OF_YEAR, chronoDate.get(MONTH_OF_YEAR)); |
|
1021 addFieldValue(fieldValues, YEAR, chronoDate.get(YEAR)); |
|
1022 } |
|
1023 } |
|
1024 |
|
1025 ChronoLocalDate resolveYearOfEra(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1026 Long yoeLong = fieldValues.remove(YEAR_OF_ERA); |
|
1027 if (yoeLong != null) { |
|
1028 Long eraLong = fieldValues.remove(ERA); |
|
1029 int yoe; |
|
1030 if (resolverStyle != ResolverStyle.LENIENT) { |
|
1031 yoe = range(YEAR_OF_ERA).checkValidIntValue(yoeLong, YEAR_OF_ERA); |
|
1032 } else { |
|
1033 yoe = Math.toIntExact(yoeLong); |
|
1034 } |
|
1035 if (eraLong != null) { |
|
1036 Era eraObj = eraOf(range(ERA).checkValidIntValue(eraLong, ERA)); |
|
1037 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); |
|
1038 } else { |
|
1039 if (fieldValues.containsKey(YEAR)) { |
|
1040 int year = range(YEAR).checkValidIntValue(fieldValues.get(YEAR), YEAR); |
|
1041 ChronoLocalDate chronoDate = dateYearDay(year, 1); |
|
1042 addFieldValue(fieldValues, YEAR, prolepticYear(chronoDate.getEra(), yoe)); |
|
1043 } else if (resolverStyle == ResolverStyle.STRICT) { |
|
1044 // do not invent era if strict |
|
1045 // reinstate the field removed earlier, no cross-check issues |
|
1046 fieldValues.put(YEAR_OF_ERA, yoeLong); |
|
1047 } else { |
|
1048 List<Era> eras = eras(); |
|
1049 if (eras.isEmpty()) { |
|
1050 addFieldValue(fieldValues, YEAR, yoe); |
|
1051 } else { |
|
1052 Era eraObj = eras.get(eras.size() - 1); |
|
1053 addFieldValue(fieldValues, YEAR, prolepticYear(eraObj, yoe)); |
|
1054 } |
|
1055 } |
|
1056 } |
|
1057 } else if (fieldValues.containsKey(ERA)) { |
|
1058 range(ERA).checkValidValue(fieldValues.get(ERA), ERA); // always validated |
|
1059 } |
|
1060 return null; |
|
1061 } |
|
1062 |
|
1063 ChronoLocalDate resolveYMD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1064 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1065 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1066 long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); |
|
1067 long days = Math.subtractExact(fieldValues.remove(DAY_OF_MONTH), 1); |
|
1068 return date(y, 1, 1).plus(months, MONTHS).plus(days, DAYS); |
|
1069 } |
|
1070 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
1071 ValueRange domRange = range(DAY_OF_MONTH); |
|
1072 int dom = domRange.checkValidIntValue(fieldValues.remove(DAY_OF_MONTH), DAY_OF_MONTH); |
|
1073 if (resolverStyle == ResolverStyle.SMART) { // previous valid |
|
1074 try { |
|
1075 return date(y, moy, dom); |
|
1076 } catch (DateTimeException ex) { |
|
1077 return date(y, moy, 1).with(TemporalAdjuster.lastDayOfMonth()); |
|
1078 } |
|
1079 } |
|
1080 return date(y, moy, dom); |
|
1081 } |
|
1082 |
|
1083 ChronoLocalDate resolveYD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1084 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1085 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1086 long days = Math.subtractExact(fieldValues.remove(DAY_OF_YEAR), 1); |
|
1087 return dateYearDay(y, 1).plus(days, DAYS); |
|
1088 } |
|
1089 int doy = range(DAY_OF_YEAR).checkValidIntValue(fieldValues.remove(DAY_OF_YEAR), DAY_OF_YEAR); |
|
1090 return dateYearDay(y, doy); // smart is same as strict |
|
1091 } |
|
1092 |
|
1093 ChronoLocalDate resolveYMAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1094 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1095 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1096 long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); |
|
1097 long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); |
|
1098 long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), 1); |
|
1099 return date(y, 1, 1).plus(months, MONTHS).plus(weeks, WEEKS).plus(days, DAYS); |
|
1100 } |
|
1101 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
1102 int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); |
|
1103 int ad = range(ALIGNED_DAY_OF_WEEK_IN_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_MONTH), ALIGNED_DAY_OF_WEEK_IN_MONTH); |
|
1104 ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); |
|
1105 if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { |
|
1106 throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); |
|
1107 } |
|
1108 return date; |
|
1109 } |
|
1110 |
|
1111 ChronoLocalDate resolveYMAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1112 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1113 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1114 long months = Math.subtractExact(fieldValues.remove(MONTH_OF_YEAR), 1); |
|
1115 long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), 1); |
|
1116 long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); |
|
1117 return resolveAligned(date(y, 1, 1), months, weeks, dow); |
|
1118 } |
|
1119 int moy = range(MONTH_OF_YEAR).checkValidIntValue(fieldValues.remove(MONTH_OF_YEAR), MONTH_OF_YEAR); |
|
1120 int aw = range(ALIGNED_WEEK_OF_MONTH).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_MONTH), ALIGNED_WEEK_OF_MONTH); |
|
1121 int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); |
|
1122 ChronoLocalDate date = date(y, moy, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); |
|
1123 if (resolverStyle == ResolverStyle.STRICT && date.get(MONTH_OF_YEAR) != moy) { |
|
1124 throw new DateTimeException("Strict mode rejected resolved date as it is in a different month"); |
|
1125 } |
|
1126 return date; |
|
1127 } |
|
1128 |
|
1129 ChronoLocalDate resolveYAA(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1130 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1131 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1132 long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); |
|
1133 long days = Math.subtractExact(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), 1); |
|
1134 return dateYearDay(y, 1).plus(weeks, WEEKS).plus(days, DAYS); |
|
1135 } |
|
1136 int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); |
|
1137 int ad = range(ALIGNED_DAY_OF_WEEK_IN_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_DAY_OF_WEEK_IN_YEAR), ALIGNED_DAY_OF_WEEK_IN_YEAR); |
|
1138 ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7 + (ad - 1), DAYS); |
|
1139 if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { |
|
1140 throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); |
|
1141 } |
|
1142 return date; |
|
1143 } |
|
1144 |
|
1145 ChronoLocalDate resolveYAD(Map<TemporalField, Long> fieldValues, ResolverStyle resolverStyle) { |
|
1146 int y = range(YEAR).checkValidIntValue(fieldValues.remove(YEAR), YEAR); |
|
1147 if (resolverStyle == ResolverStyle.LENIENT) { |
|
1148 long weeks = Math.subtractExact(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), 1); |
|
1149 long dow = Math.subtractExact(fieldValues.remove(DAY_OF_WEEK), 1); |
|
1150 return resolveAligned(dateYearDay(y, 1), 0, weeks, dow); |
|
1151 } |
|
1152 int aw = range(ALIGNED_WEEK_OF_YEAR).checkValidIntValue(fieldValues.remove(ALIGNED_WEEK_OF_YEAR), ALIGNED_WEEK_OF_YEAR); |
|
1153 int dow = range(DAY_OF_WEEK).checkValidIntValue(fieldValues.remove(DAY_OF_WEEK), DAY_OF_WEEK); |
|
1154 ChronoLocalDate date = dateYearDay(y, 1).plus((aw - 1) * 7, DAYS).with(nextOrSame(DayOfWeek.of(dow))); |
|
1155 if (resolverStyle == ResolverStyle.STRICT && date.get(YEAR) != y) { |
|
1156 throw new DateTimeException("Strict mode rejected resolved date as it is in a different year"); |
|
1157 } |
|
1158 return date; |
|
1159 } |
|
1160 |
|
1161 ChronoLocalDate resolveAligned(ChronoLocalDate base, long months, long weeks, long dow) { |
|
1162 ChronoLocalDate date = base.plus(months, MONTHS).plus(weeks, WEEKS); |
|
1163 if (dow > 7) { |
|
1164 date = date.plus((dow - 1) / 7, WEEKS); |
|
1165 dow = ((dow - 1) % 7) + 1; |
|
1166 } else if (dow < 1) { |
|
1167 date = date.plus(Math.subtractExact(dow, 7) / 7, WEEKS); |
|
1168 dow = ((dow + 6) % 7) + 1; |
|
1169 } |
|
1170 return date.with(nextOrSame(DayOfWeek.of((int) dow))); |
1035 } |
1171 } |
1036 |
1172 |
1037 /** |
1173 /** |
1038 * Adds a field-value pair to the map, checking for conflicts. |
1174 * Adds a field-value pair to the map, checking for conflicts. |
1039 * <p> |
1175 * <p> |