Reputation: 1375
Java 8's DateTimeFormatter
class has a method, ofPattern(String pattern)
, that lets you define a format from a string of A-z
, a-z
letters. The examples don't clarify the difference between y
, year-of-era and Y
, week-based-year. What is it?
Symbol Meaning Presentation Examples
------ ------- ------------ -------
y year-of-era year 2004; 04
Y week-based-year year 1996; 96
Upvotes: 109
Views: 28567
Reputation: 46
I like @xxks-kkk answer. If you are interesting which week definition is used for your Locale, you can check it easily.
In brief:
Definition of the week and to which year it belongs to depends on two values:
This two values are encapsulated in WeekFields
class.
The following code prints all possible WeekFields
with all assigned to it Locale
s.
public class PrintLocaleWeekFields {
public static void main(String[] args) {
Map<WeekFields, List<Locale>> locales = Arrays.stream(Locale.getAvailableLocales())
.collect(Collectors.groupingBy(WeekFields::of));
System.out.println(locales);
}
}
Printed result:
WeekFields[MONDAY,1]=[tk_TM_#Latn, en_NU, ff_LR_#Adlm, es_BO, bs_BA, en_LR, ar_TD, nus_SS_#Latn, ff_MR_#Latn, sw_UG, tk_TM, sr_ME_#Cyrl, os_GE_#Cyrl, yo_NG, en_PW, sr_CS, agq_CM_#Latn, ar_EH, bs_BA_#Latn, dje_NE, hy_AM_#Armn, ff_GH_#Latn, fr_PM, ar_KM, agq_CM, tr_TR, kl_GL_#Latn, ar_MR, kl_GL, en_NR, rw_RW_#Latn, en_CY, tr_TR_#Latn, ti_ER, nus_SS, en_RW, hr_HR_#Latn, ln_CD, nnh_CM, dje_NE_#Latn, ksf_CM, fr_VU, nnh_CM_#Latn, fr_NE, bez_TZ_#Latn, ksb_TZ, ln_CF, en_CX, ak_GH_#Latn, en_TZ, fr_NC, fr_CM, pcm_NG_#Latn, teo_UG, ln_CG, az_AZ, el_CY, ku_TR, ff_SN, sq_MK, sr_BA_#Cyrl, so_SO_#Latn, tr_CY, lv_LV_#Latn, uz_UZ_#Latn, dua_CM, fr_TN, sr_RS, sw_TZ_#Latn, fr_PF, pt_GQ, vun_TZ, jmc_TZ, mg_MG_#Latn, en_TV, en_PN, lu_CD_#Latn, en_GY, dyo_SN, nl_CW, fr_GQ, en_NG, fr_CI, ia_001, en_LC, ff_BF_#Adlm, bm_ML_#Latn, yav_CM_#Latn, mk_MK, sl_SI, sg_CF_#Latn, jgo_CM, ff_NE_#Adlm, en_BM, kea_CV, vi_VN, mfe_MU, fr_BF, fr_YT, ff_CM_#Latn, sr_BA_#Latn, uk_UA_#Cyrl, ff_GW_#Adlm, ha_GH, yi_001_#Hebr, to_TO_#Latn, ff_GW_#Latn, mua_CM_#Latn, nyn_UG, ms_MY, rn_BI_#Latn, ta_LK, tg_TJ, vun_TZ_#Latn, es_EC, mk_MK_#Cyrl, ff_CM_#Adlm, lg_UG, ff_NE_#Latn, cgg_UG, pcm_NG, en_BI, mi_NZ, ar_ER, es_EA, fr_SC, en_SL, ff_NG_#Latn, ff_NG_#Adlm, en_SH, eo_001, en_SI, vai_LR_#Vaii, rof_TZ_#Latn, ar_LB, ff_GN, eo_001_#Latn, hr_HR, rof_TZ, mn_MN, en_FM, fr_WF, ff_GM_#Latn, teo_UG_#Latn, asa_TZ_#Latn, bez_TZ, ff_GN_#Latn, sl_SI_#Latn, en_FK, bas_CM_#Latn, en_DG, pt_ST, ak_GH, es_419, ln_CD_#Latn, kkj_CM_#Latn, es_IC, ar_TN, bm_ML, jmc_TZ_#Latn, khq_ML, en_SB, rw_RW, shi_MA_#Tfng, ro_MD, uz_UZ, ia_001_#Latn, en_SC, en_UG, en_NZ, es_UY, ru_UA, sg_CF, en_BB, hr_BA, yo_NG_#Latn, lu_CD, ar_001, so_SO, lv_LV, sr_RS_#Cyrl, en_LS, ka_GE, sw_TZ, fr_RW, mg_MG, sr_RS_#Latn, ky_KG, tzm_MA_#Latn, ku_TR_#Latn, mfe_MU_#Latn, ky_KG_#Cyrl, qu_EC, ka_GE_#Geor, en_MS, kde_TZ_#Latn, sr_ME, en_ZM, fr_ML, ha_NG, os_GE, yi_001, en_GH, tzm_MA, ses_ML, rwk_TZ_#Latn, vai_LR_#Latn, sw_CD, ff_MR_#Adlm, en_VC, ses_ML_#Latn, en_150, ha_NE, en_KN, ro_RO, sr_ME_#Latn, ff_LR_#Latn, bas_CM, fr_MG, es_CL, sq_AL, ro_RO_#Latn, twq_NE, nmg_CM, en_MP, en_GD, sbp_TZ_#Latn, kde_TZ, ta_MY, si_LK_#Sinh, en_KI, twq_NE_#Latn, sq_AL_#Latn, ff_GH_#Adlm, fr_MF, en_SZ, rwk_TZ, kk_KZ, ar_PS, kkj_CM, es_GQ, en_SX, ru_KZ, ko_KP, nl_SR, bem_ZM_#Latn, cgg_UG_#Latn, nl_BQ, ee_GH_#Latn, ff_GN_#Adlm, uz_UZ_#Cyrl, asa_TZ, fr_SN, fr_MA, ff_GM_#Adlm, fr_BL, mgo_CM, nmg_CM_#Latn, tg_TJ_#Cyrl, en_SS, shi_MA, en_MG, fr_BI, naq_NA_#Latn, fr_BJ, vai_LR, bs_BA_#Cyrl, khq_ML_#Latn, mn_MN_#Cyrl, wo_SN, ha_NG_#Latn, fr_HT, nl_SX, fr_CG, ms_MY_#Latn, zgh_MA_#Tfng, nyn_UG_#Latn, en_VU, to_TO, ff_SL_#Latn, xog_UG_#Latn, ff_SN_#Adlm, vi_VN_#Latn, jgo_CM_#Latn, zgh_MA, uk_UA, lg_UG_#Latn, en_NF, sr_XK_#Cyrl, ar_SS, nl_AW, en_AI, xog_UG, en_CM, ru_MD, ff_SN_#Latn, en_TO, ff_SL_#Adlm, en_PG, fr_CF, pt_TL, en_ER, sr_BA, be_BY_#Cyrl, fr_TG, sr_XK_#Latn, ig_NG, fr_GN, en_CK, ar_MA, fr_TD, bem_ZM, ewo_CM_#Latn, ewo_CM, fr_CD, rn_BI, en_NA, mgo_CM_#Latn, lag_TZ, qu_BO, kea_CV_#Latn, sq_XK, mi_NZ_#Latn, en_KY, si_LK, ar_SO, fr_MU, en_TK, mua_CM, pt_GW, ee_TG, ln_AO, be_BY, pt_CV, ru_BY, ee_GH, kk_KZ_#Cyrl, yo_BJ, fr_KM, es_AR, en_MY, sbp_TZ, hy_AM, en_GM, ksb_TZ_#Latn, pt_AO, en_001, dua_CM_#Latn, lag_TZ_#Latn, ru_KG, fr_MR, ksf_CM_#Latn, ff_BF_#Latn, en_MW, naq_NA, en_IO, en_CC, az_AZ_#Cyrl, shi_MA_#Latn, es_CU, ig_NG_#Latn, yav_CM, da_GL, wo_SN_#Latn, es_CR, fr_GA, en_MU, az_AZ_#Latn, dyo_SN_#Latn, en_VG, en_TC, af_NA, mas_TZ, ms_BN],
WeekFields[SATURDAY,1]=[ar_EG, ps_AF_#Arab, ar_SY, uz_AF, lrc_IR, ar_OM, lrc_IQ, ar_DZ, fa_IR_#Arab, fr_DJ, so_DJ, lrc_IR_#Arab, ar_AE, mzn_IR, en_SD, uz_AF_#Arab, ar_IQ, ar_KW, ar_JO, fr_DZ, fa_AF, ckb_IQ_#Arab, ar_SD, fa_IR, kab_DZ_#Latn, kab_DZ, ps_AF, mzn_IR_#Arab, en_AE, ar_BH, ar_QA, ar_EG_#Arab, ckb_IQ, ckb_IR, ar_LY, fr_SY, ar_DJ],
WeekFields[MONDAY,4]=[se_NO_#Latn, dsb_DE, lb_LU_#Latn, se_NO, pl_PL, nds_DE, nb_SJ, lb_LU, dsb_DE_#Latn, is_IS_#Latn, no_NO_NY, pl_PL_#Latn, nds_DE_#Latn, tt_RU, fur_IT_#Latn, ast_ES_#Latn, en_JE, da_DK_#Latn, en_AT, gd_GB, wae_CH_#Latn, no_NO_#Latn, smn_FI_#Latn, en_NL, gsw_FR, hu_HU, bg_BG_#Cyrl, et_EE, fy_NL, de_IT, de_CH, nl_NL, pt_CH, gv_IM, kw_GB_#Latn, fi_FI_#Latn, fr_BE, nb_NO, it_SM, fi_FI, ca_FR, de_BE, de_DE_#Latn, fr_FR_#Latn, ksh_DE, ru_RU, ga_IE, rm_CH_#Latn, fr_LU, ga_GB, no_NO, de_LU, de_DE, nn_NO_#Latn, en_DK, lt_LT, ksh_DE_#Latn, da_DK, en_BE, tt_RU_#Cyrl, ga_IE_#Latn, is_IS, en_SE, gsw_LI, kw_GB, en_DE, en_FI, sah_RU_#Cyrl, en_FJ, de_LI, smn_FI, de_AT, ce_RU, os_RU, nl_NL_#Latn, gl_ES_#Latn, en_GG, sv_SE, el_GR_#Grek, it_VA, es_ES, bg_BG, hsb_DE, eu_ES_#Latn, sv_SE_#Latn, sv_FI, en_IE, fo_FO_#Latn, en_GB, fr_MC, ce_RU_#Cyrl, gsw_CH, pt_LU, hsb_DE_#Latn, br_FR_#Latn, es_ES_#Latn, cy_GB_#Latn, fr_FR, sah_RU, sk_SK, ru_RU_#Cyrl, gv_IM_#Latn, nds_NL, fr_RE, fr_GP, fr_CH, nb_NO_#Latn, fy_NL_#Latn, cs_CZ, ca_ES, hu_HU_#Latn, rm_CH, et_EE_#Latn, gd_GB_#Latn, se_FI, lt_LT_#Latn, ca_IT, ca_AD, it_CH, it_IT, nn_NO, se_SE, it_IT_#Latn, wae_CH, fo_DK, en_CH, fo_FO, ast_ES, fr_MQ, fur_IT, fr_GF, sk_SK_#Latn, eu_ES, el_GR, ca_ES_VALENCIA, gl_ES, en_IM, gsw_CH_#Latn, en_GI, ca_ES_#Latn, nl_BE, cy_GB, sv_AX, cs_CZ_#Latn, br_FR],
WeekFields[SUNDAY,1]=[, he, th_TH_#Thai, nds, ti_ET, ta_SG, lv, zh_SG_#Hans, en_JM, kkj, sd__#Arab, dz_BT, mni, yi, cs, el, af, smn, dsb, khq, ne_IN, es_US, sa, en_US_POSIX, pt_MO, zh__#Hans, so_KE, gu_IN_#Gujr, teo, eu, es_DO, ru, az, su__#Latn, fa, nd, kk, hy, en_AU, ksb, luo, lb, su, no, ar_IL, mgh, or_IN, az__#Latn, ta, lag, luo_KE_#Latn, bo, om_KE, en_AS, zh_TW, sd_IN, kln, mai, pt_MZ, my_MM_#Mymr, gl, sr__#Cyrl, yue_CN_#Hans, ff__#Adlm, kn_IN, ga, qu, en_PR, mua, jv, ps, sn, km, zgh, es, jgo, gsw, pa_IN_#Guru, ur_PK_#Arab, ceb, bn_BD_#Beng, ne_NP_#Deva, te, sl, mr_IN, ha, guz_KE_#Latn, es_HN, sbp, sw, nmg, pt_BR_#Latn, vai__#Vaii, gu, lo, zh_HK_#Hans, bs__#Latn, os, am, ki_KE, en_PK, zh_CN, rw, brx_IN, en_TT, dav, ses, xh_ZA, es_VE, mer_KE, mg, mr, seh, mgo, en_US, pa__#Guru, sa_IN_#Deva, gu_IN, ast, mt_MT_#Latn, yue__#Hans, ccp_BD_#Cakm, ks__#Arab, af_ZA_#Latn, ti_ET_#Ethi, am_ET_#Ethi, cgg, zh_MO, ksf, cy, ceb_PH, sq, fr, qu_PE, de, zu_ZA, su_ID_#Latn, lg, en_DM, sd, he_IL_#Hebr, yue_CN, en_WS, so, kab, nus, sn_ZW, th_TH_TH_#u-nu-thai, hi, zh_MO_#Hant, vai, sd_PK_#Arab, mi, mt, yav, kam, ro, ps_PK, ee, en_UM, lo_LA, chr, af_ZA, doi, es_BZ, as, it, ks_IN, my_MM, ur_PK, ii, naq, en_SG, kln_KE, tzm, fur, om, mai_IN_#Deva, ja_JP_JP_#u-ca-japanese, es_SV, pt_BR, mni_IN_#Beng, ml_IN, hr, lt, ccp, zh_CN_#Hans, en, guz_KE, ccp_BD, ca, pa_PK, ug_CN, ki_KE_#Latn, es_BR, bo_CN_#Tibt, chr_US, nyn, mk, sat, pa__#Arab, bs, fy, th, dav_KE, dje, mas_KE, mni_IN, ckb, bem, da, wae, ig, en_HK, brx_IN_#Deva, mer_KE_#Latn, en_US_#Latn, ki, nb, kok, ewo, nn, bg, kea, zu, am_ET, bo_CN, hsb, kok_IN_#Deva, sat_IN, pcm, sah, mer, br, ar_SA, fil_PH_#Latn, sk, om_ET_#Latn, ml, en_MT, en_IL, sv, kn_IN_#Knda, lkt_US, sd__#Deva, ku, fil_PH, es_PH, es_CO, agq, ebu, es_GT, nd_ZW_#Latn, mn, kam_KE, en_MO, ja_JP_#Jpan, wo, shi__#Tfng, en_BZ, lkt_US_#Latn, ta_IN_#Taml, az__#Cyrl, tk, shi__#Latn, en_BW, he_IL, nd_ZW, luy_KE_#Latn, mni__#Beng, ne, zh_SG, om_ET, lo_LA_#Laoo, ja_JP, kam_KE_#Latn, my, ka, ko_KR_#Kore, ms_ID, shi, kl, sa_IN, yue_HK, id, zh, es_PE, mgh_MZ, saq, zh_HK_#Hant, sat_IN_#Olck, es_PA, bez, kw, vai__#Latn, ksh, ur_IN, ln, luy_KE, pt, mgh_MZ_#Latn, ar_YE, to, et, rof, en_BS, be, gv, kln_KE_#Latn, dua, hi_IN_#Deva, guz, en_KE, mfe, ja, or, brx, mai_IN, ko_KR, es_MX, zu_ZA_#Latn, doi_IN, fi, uz, bs__#Cyrl, sr__#Latn, bo_IN, rm, bn, kn, nnh, bn_BD, en_ZA, pa_IN, en_MH, zh__#Hant, jv_ID_#Latn, ky, mas, xh_ZA_#Latn, dav_KE_#Latn, xh, te_IN, mas_KE_#Latn, lrc, ce, mt_MT, ko, ml_IN_#Mlym, ak, kde, dz, ia, seh_MZ, su_ID, ii_CN, pa_PK_#Arab, bn_IN, pa, rwk, rn, tg, hu, ceb_PH_#Latn, twq, bm, en_GU, tr, es_PY, kok_IN, dz_BT_#Tibt, en_PH, zh_MO_#Hans, sat__#Olck, ff, haw_US_#Latn, en_AG, ebu_KE, xog, ms, ug, qu_PE_#Latn, id_ID, teo_KE, haw_US, vi, fr_CA, dyo, luo_KE, eo, en_ZW, pl, ur, uz__#Arab, saq_KE, se, sn_ZW_#Latn, ms_SG, yue__#Hant, km_KH_#Khmr, luy, uk, es_PR, mzn, tt, ug_CN_#Arab, hi_IN, saq_KE_#Latn, asa, ff__#Latn, doi_IN_#Deva, ebu_KE_#Latn, uz__#Cyrl, fil, yue_HK_#Hant, fo, ne_NP, ta_IN, lkt, id_ID_#Latn, is, te_IN_#Telu, si, jv_ID, ks, zh_TW_#Hant, as_IN, zh_HK, sw_KE, th_TH, as_IN_#Beng, jmc, yue, ar, en_VI, haw, bas, uz__#Latn, sg, km_KH, nl, ks_IN_#Arab, sd_IN_#Deva, mr_IN_#Deva, sr, seh_MZ_#Latn, en_CA, gd, chr_US_#Cher, or_IN_#Orya, so_ET, vun, en_IN, lu, yo, es_NI, ii_CN_#Yiii, sd_PK, ti, ccp_IN],
WeekFields[SUNDAY,4]=[pt_PT]}
Upvotes: 0
Reputation: 338634
Some other Answers are quite interesting, but complicated. Here is a hopefully simpler Answer to get your oriented.
y
and u
(lowercase)The y
character for year-of-era is simply the calendar year, the regular year used across the West and much of the world, based on the Gregorian calendar.
The DateTimeFormatter
class also uses a u
for the nearly the same thing. For contemporary dates, there is no difference. For the nitty-gritty details, see uuuu
versus yyyy
in DateTimeFormatter
formatting pattern codes in Java?.
For the regular dates we use in quotidian life, you would parse or generate text representing date values using a formatting pattern such as:
DateTimeFormatter.ofPattern( "dd/MM/yyyy" ) ;
…or…
DateTimeFormatter.ofPattern( "dd/MM/uuuu" ) ;
In either case, Monday, December 30, 2019 would be parsed like this:
LocalDate localDate = LocalDate.parse( "30/12/2019" ) ;
localDate.toString(): 2019-12-30
Y
(uppercase)Many people in various industries find it useful to track time by week, assigning a number to each week of the year.
There are various ways to define a week, such as starting on a Sunday or on a Monday. So there are various ways to define a week of the year. Does week # 1 have the January 1st? Or does week # 1 have the first Sunday of the year?
The ISO 8601 standard defines a week as starting on a Monday. Week number 1 has the first Thursday of the new calendar year.
This definition means week-based year has either 52 or 53 whole weeks, always 7-days long (Monday-Sunday),for a year length of either 364 days or 371 days. In contrast, a calendar year has either 365 or 366 days crossing 52 partial weeks.
So the date 2019-12-30 (Monday, December 30, 2019) is actually in the first week of week-based year of 2020.
YYYY
for that date of 2019-12-30 in your formatting pattern.yyyy
.The ISO 8601 standard defines a specific format for representing a date within a week of a week-based year: YYYY-Www-d where the YYYY
is the week-based year, the -W
is fixed, the ww
represents the week number 1-52 or 1-53, and the d
represents a day-of-week running 1-7 for Monday-Sunday.
So Monday, December 30, 2019 is: 2020-W01-1
meaning week-based year 2020, first week of the year, and first day of the week (Monday).
To parse the ISO 8601 week with day-of-week number, we can use DateTimeFormatter
. No need to define a formatting pattern with YYYY
, as this work has already been done for you. Use the builtin DateTimeFormatter.ISO_WEEK_DATE
.
String output = localDate.format( DateTimeFormatter.ISO_WEEK_DATE ) ;
2020-W01-1
Likewise, parsing.
LocalDate localDate =
LocalDate.parse(
"2020-W01-1" ,
DateTimeFormatter.ISO_WEEK_DATE
)
;
localDate.toString(): 2019-12-30
The ThreeTen-Extra library adds functionality to the java.time classes built into Java.
org.threeten.extra.YearWeek
That library provides the YearWeek
class. Just what you need if you are working with weeks of week-based year according to the ISO 8601 definition of a week and week-based year.
This class can translate back and forth between the regular date format and the week-oriented format.
LocalDate localDate = LocalDate.of( 2019 , Month.DECEMBER , 30 ) ; // Monday 2019-12-30. Its week-based year is 2020.
YearWeek yearWeek = YearWeek.from( localDate ) ;
String wFormatted = yearWeek.toString() ;
2020-W01
Get a date from that.
LocalDate localDate = yearWeek.atDay( DayOfWeek.MONDAY ) ;
localDate.toString(): 2019-12-30
Upvotes: 48
Reputation: 86276
I didn’t find it perfectly clear from the other answers, so allow me to give my shot.
The week-based year or sometimes week year for short is the year that the relevant week number belongs to. So for example all of the days of week 1 have the same week-based year even if some of the week lies in the previous calendar year. Or the other way around, say that week 52 of a year stretches into the following year (which is possible with some, not all week numbering schemes), then every day of that week has the old calendar year as its week-based year. Where I live, week 1 of 2020 was from Monday December 30 to Sunday January 5, inclusive. So for the days up to December 29, calendar year and week-based year agreed to be 2019. December 30 and 31 had week-based year 2020, but of course still calendar year 2019. From January 1 calendar year and week-based year again agreed, now at 2020.
So the week-based year hardly has any meaningful use except together with a week number.
Where it gets a bit complicated (and where I think the other answers are not quite clear) is that week numbering is locale dependent, and therefore week-based year is too. A DateTimeFormatter
has a locale and uses this locale for selecting the week numbering scheme to use when deciding the week-based year for a given date.
To illustrate I am formatting 10 days around New Year 2022 in three different locales:
My code:
DateTimeFormatter iso
= DateTimeFormatter.ofPattern("Y w E", Locale.FRANCE);
DateTimeFormatter us
= DateTimeFormatter.ofPattern("Y w E", Locale.US);
DateTimeFormatter arabic = DateTimeFormatter
.ofPattern("Y w E", Locale.forLanguageTag("ar-MA"));
System.out.println(" ISO US Morocco");
LocalDate d = LocalDate.of(2021, Month.DECEMBER, 25);
for (int i = 0; i < 10; i++) {
System.out.format("%-10s %-12s %-11s %s%n",
d, d.format(iso), d.format(us), d.format(arabic));
d = d.plusDays(1);
}
Output:
ISO US Morocco
2021-12-25 2021 51 sam. 2021 52 Sat 2021 53 السبت
2021-12-26 2021 51 dim. 2022 1 Sun 2021 53 الأحد
2021-12-27 2021 52 lun. 2022 1 Mon 2021 53 الاثنين
2021-12-28 2021 52 mar. 2022 1 Tue 2021 53 الثلاثاء
2021-12-29 2021 52 mer. 2022 1 Wed 2021 53 الأربعاء
2021-12-30 2021 52 jeu. 2022 1 Thu 2021 53 الخميس
2021-12-31 2021 52 ven. 2022 1 Fri 2021 53 الجمعة
2022-01-01 2021 52 sam. 2022 1 Sat 2022 1 السبت
2022-01-02 2021 52 dim. 2022 2 Sun 2022 1 الأحد
2022-01-03 2022 1 lun. 2022 2 Mon 2022 1 الاثنين
Observations;
For the sake of completeness: Defining week numbering has two parts:
In both US and Morocco week 1 is defined as the week containing January 1. In other words, a week just needs to have at least 1 day in the new year for it to be week 1 of that new year. Not so in ISO. You see that January 1 in France belongs to week 52 of the old year. Here a week belongs to the year where the majority of its days lie (since there are 7 days in a week, an odd number, there will never be a tie). In other words, a week must have at least 4 (four) of its days in the new year for it to be week 1.
Upvotes: 0
Reputation: 736
That's year value for "year-week" style dates, as in 2006-W52. It may be off the year-of-era value by +1 or -1 if the week in question straddles year boundary.
See http://en.wikipedia.org/wiki/ISO_8601#Week_dates
Upvotes: 68
Reputation: 2608
What Y
suggests is that we want to format a given date according to ISO 8601 week-numbering year. According to wikipedia, the definition of week 01 is
the week with the year's first Thursday in it (the formal ISO definition)
and thus,
The first ISO week of a year may have up to three days that are actually in the Gregorian calendar year that is ending
Let's consider "2019-12-30" date, which is a Monday.
If we take a look at that week, we have December 30 & 31 of 2019 are Monday and Tuesday; January 1-4 of 2020 are Wednesday, Thursday, Friday, and Saturday. As you can see, this week spans Gregorian calendar year (a calendar system we use) 2019 and Gregorian calendar year 2020. If we apply definition of week01 of week-based year above, we can see that the week between 12/30/2019 and 01/05/2020 is week01 of week-based year 2020 (ISO standard specifies that the beginning of a week is Monday). Thus, if we want to parse "2019-12-30" with dateTimeFormatter 'YYYY-MM-dd'
, the correct result is '2020-12-30'
. However, with 'yyyy-MM-dd'
, the end result will be '2019-12-30'
.
System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("YYYY-MM-dd"))); // output "2020-12-30"
System.out.println(LocalDate.parse("2019-12-30").format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); // output "2019-12-30"
I think there might be a potential problem with Java implementation. If we consider example given by Sam Berry above, the output of "2019-12-29" doesn't consistent with how week-based year is defined. The reason is that "2019-12-29" is a Sunday. If we apply definition from Wikipedia above, "2019-12-29" should be parsed as "2019-12-29" even given 'YYYY-MM-dd'
. This is because beginning of week01 is Monday rather than Sunday by ISO standard. If we look up week numbers for 2020, we can see week 01 of 2020 starts at "2019-12-30". I suspect this is possibly due to the implementer of API consider the beginning of a week is Sunday, which is not true according to ISO standard.
UPDATE
On the suspect of Java implementation error. It is not implementation error. Thanks for Ole V.V. comment below. During the formatting, there is subtle dependency on how the beginning of week01 is defined, which is relfected by Locale
. For example, if the locale is europe, the beginning of a week is Monday, which is consistent with ISO standard. Thus
System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.FRANCE)));
has output 2019-12-29
. However, in the U.S., the beginning of a week is considered as Sunday. Thus
System.out.println(LocalDate.of(2019, Month.DECEMBER, 29).format(DateTimeFormatter.ofPattern("YYYY-MM-dd", Locale.US)));
has output 2020-12-29
.
Upvotes: 2
Reputation: 7844
A concept where a week only belongs to 1 year. For example:
LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/Y"))
---> "12/29/2020"`
The common use of year, 1/1 always being the first day of the year. For example:
LocalDate.parse("2019-12-29").format(DateTimeFormatter.ofPattern("M/d/y"))
---> "12/29/2019"
Upvotes: 1
Reputation: 63385
Each field is documented in a "field" class, such as ChronoField
, WeekFields
or IsoFields
.
The "year-of-era" field is documented in ChronoField
.
The "week-based-year" field is documented in WeekFields
.
Upvotes: 10