android java, week number of a date is incorrect - java

in my android app I'm working on to get the week number of a provided date. but it doesn't give me the correct week number I'm using following code to get the week number.
String format = "dd-MM-yyyy";
SimpleDateFormat df = new SimpleDateFormat(format);
Date date = df.parse(date);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int week = cal.get(Calendar.WEEK_OF_YEAR);
but this not give me what I'm expecting. for instance lets take January 2016.
As of January 2016 as seen from the above calendar, days belongs to the week number 1 are only 1st,2nd and 3rd. and for the week number 2, relevant days are 4th, 5th, 6th, 7th,8th, 9th and 10th. then for the week number 3, relevant days are 11th, 12th, 13th, 14th, 15th, 16th and 17th and so on. but for the date 12/01/2016 above code gives me week number 2 instead of week number 3. am I doing something wrong or is this the way the function works normally. how can I meet my goal to get the week number as I mention above.

1st, 2nd and 3rd of January are actually week 53 of year 2015. The code is working correctly, your assumptions about week numbering are wrong. The default behaviour of GregorianCalendar is the same as ISO definition for the first week in Wikipedia:
The ISO 8601 definition for week 01 is the week with the year's first
Thursday in it. The following definitions based on properties of this
week are mutually equivalent, since the ISO week starts with Monday:
It is the first week with a majority (4 or more) of its days in January.
Its first day is the Monday nearest to 1 January.
It has 4 January in it. Hence the earliest possible dates are 29 December through 4 January, the latest 4 through 10 January.
It has the year's first working day in it, if Saturdays, Sundays and 1 January are not working days.
If 1 January is on a Monday, Tuesday, Wednesday or Thursday, it is in
week 01. If 1 January is on a Friday, it is part of week 53 of the
previous year; if on a Saturday, it is part of week 52 (or 53 if the
previous year was a leap year); if on a Sunday, it is part of week 52
of the previous year.

Found at https://docs.oracle.com/javase/7/docs/api/java/util/GregorianCalendar.html :
Values calculated for the WEEK_OF_YEAR field range from 1 to 53. The first week of a calendar year is the earliest seven day period starting on getFirstDayOfWeek() that contains at least getMinimalDaysInFirstWeek() days from that year. It thus depends on the values of getMinimalDaysInFirstWeek(), getFirstDayOfWeek(), and the day of the week of January 1.
So your first week will be week 0 because it starts counting from your first full 7 days week. You can change this by setting getMinimalDaysInFirstWeek() to a lower value

Related

Why does the thirteen.org date library return dates in the same year for a 53-week year (for week 53)?

Using the https://www.threeten.org/threeten-extra library.
When computing the first Sunday of the month, given week number and year, I noticed that if I used 2018 and week 53, I get as the result the first Sunday 2018-12-02.
Yet, 2018 is not a 53-week year so I am wondering if I'm doing something wrong or perhaps there's something special about 2018? I didn't see that the week start date or other 53-week conditions were met, but I could have missed something.
In other tests like 2011 (also not a and week 53-week year), the date logic wraps the result as expected to 2012-01-01 (the first Sunday in the first week of the next year).
Years 2020, 2015, and 2019 (all 53-week years) display the result value as expected in December of the respective year.
Here is the code:
YearWeek yw = YearWeek.of(year, weekNumber);
//Get the date of the first day of that week.
LocalDate ld = yw.atDay( DayOfWeek.MONDAY ) ;
// Use a TemporalAdjuster to get nth day-of-week of that month date’s month.
TemporalAdjuster ta = TemporalAdjusters.dayOfWeekInMonth( 1 , DayOfWeek.SUNDAY ) ;
// TemporalAdjuster ta = TemporalAdjusters.firstDayOfMonth();
LocalDate firstSunday = ld.with( ta ) ;
return firstSunday.toString();
Suggestions?
This is what YearWeek.of does:
Obtains an instance of YearWeek from a week-based-year and week.
If the week is 53 and the year does not have 53 weeks, week one of the following year is selected.
Therefore, for (2018, 53), it selects the first week of 2019, because 2018 only has 52 weeks. This is the week starting from 2018-12-31 and ending at 2019-01-06.
You then get the Monday of this week, which is 2018-12-31, and adjusts this date to the first Sunday of the month. "The month" here being December, you get 2018-12-02 as a result.
Similarly, for (2011, 53), you get the first week of 2012 because 2011 only has 52 weeks. But unlike 2019, this is the week starting from 2012-01-02 and ending at 2012-01-08, so there is no problem.
So what's "special" about 2018? Its last week ends before the last day of the year, I suppose? This causes the first week of the next year to start in December.

SimpleDateFormat wrong week of year for last week

I need to get week of year for a given date. Using SimpleDateFormat produces wrong results for the last week of the year.
Example:
This produces week 52 correctly:
SimpleDateFormat w = new SimpleDateFormat("w");
Calendar c = Calendar.getInstance();
c.set(2021, 11, 25);
System.out.println("Week: ${w.format(c.getTime())}");
produces: Week: 52
But the next day is already considered as 1st week of next year?
SimpleDateFormat w = new SimpleDateFormat("w");
Calendar c = Calendar.getInstance();
c.set(2021, 11, 26);
System.out.println("Week: ${w.format(c.getTime())}");
produces: Week: 1
This only happens in Java 7 and not in Java 8 and above!
Don't use Calendar. It's obsolete, and, more to the point, incredibly bad API.
There's a list as long as my leg as to what's wrong with it. The specific one of about 200 things that is relevant here is that, boneheadedly, its month value is 0 indexed. So, '12, 3'? That's the 3rd of Undecimber, or whatever you'd like to call the 13th month. That, or the calendar doesn't do 13th month in which case it leniently just assumes you meant to say 3rd of jan 2022 . Either way, that's week 1.
So why is The 2nd of undecimber (or if you prefer, via rollover, 2nd jan 2022) "Week 52"?
Because it is.
Week numbering is weird, but they have to be. A week starts on monday (or sunday, for my silly standards loving USian brethren), and can't start on any other day. That means unless Jan 1st so happens to fall on a monday, there's going to be weirdness; either days in 2021 counting as being in 'week 1 of 2022', or days in 2022 counting as 'week 52 of 2021'. In fact, from time to time there'll have to be a week 53. After all, 52*7 is 364, but there are 365.2475 days in a year, so unless you just want to make some days poof out of existence, every so often a week 53 has to exist for it all to add up.
Use java.time instead.
LocalDate ld = LocalDate.of(2021, 12, 3);
WeekFields wf = WeekFields.of(Locale.ENGLISH);
int weekNumber = ld.get(wf.weekOfWeekBasedYear());
java.time does many things fantastically, and one of the things is does great is that it tends not to hide complex things. For example, 'when does a week start' is just not answerable, not unless you tell me where on the planet you're asking this question. Hence, 'which week is it' is also not actually an answerable question until you tell me exactly which week-counting system we're using, and there is no standard that is universally accepted enough. Hence, you have to go through the rigamarole of making a separate WeekFields instance to capture that info. We do it here based on locale.
Actually this is not specific to Calendar as this would also show Week 1 if ran on the 29th of December for example:
System.out.println("Week: ${new SimpleDateFormat("w").format(new Date())}");
But it is specific to Java 7. It was fixed in Java 8.
And I found the explanation for this here (as #rzwitserloot also explained):
https://docs.oracle.com/javase/8/docs/api/java/util/GregorianCalendar.html
A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between
the first and last weeks (inclusive) have the same week year value.
Therefore, the first and last days of a week year may have different
calendar year values.
For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is
MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard
compatible setting), then week 1 of 1998 starts on December 29, 1997,
and ends on January 4, 1998. The week year is 1998 for the last three
days of calendar year 1997. If, however, getFirstDayOfWeek() is
SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on
January 10, 1998; the first three days of 1998 then are part of week
53 of 1997 and their week year is 1997.
This is really interesting..

Why Java calender object return wrong WEEK_OF_YEAR and WEEK_OF_MONTH

By the following way I set date object to calendar instance.
But when I get the week of year , wrongly it returns week of the year as 1.
Same as week of the year, week of the month value also wrong. It return as 6. But it should be 5.
Following is output of calendar instance value
java.util.GregorianCalendar[time=1514678400000,
areFieldsSet=true,
areAllFieldsSet=true,
lenient=true,
zone=sun.util.calendar.ZoneInfo[id="UTC",
offset=0, dstSavings=0, useDaylight=false, transitions=0, lastRule=null],
firstDayOfWeek=1, minimalDaysInFirstWeek=1, ERA=1, YEAR=2017, MONTH=11, WEEK_OF_YEAR=1, WEEK_OF_MONTH=6, DAY_OF_MONTH=31, DAY_OF_YEAR=365, DAY_OF_WEEK=1, DAY_OF_WEEK_IN_MONTH=5, AM_PM=0, HOUR=0, HOUR_OF_DAY=0, MINUTE=0, SECOND=0, MILLISECOND=0, ZONE_OFFSET=0, DST_OFFSET=0]
firstDayOfWeek=1 means that Sunday is the first day of the week. So Sunday December 31, 2017 belonged to week 1 of 2018.
It’s not well documented, but it turns out that the week of month follows the month, so on Dec 31, it gives you the number of the week in December. Since December 1 and 2 were Friday and Saturday, they formed week 1 of December. Week 2 began on December 3. So week 6 began on December 31 and lasted only that day. This explains why week of month is 6 in your case.
Whether we use IST time zone (I am assuming it means Asia/Kolkata) or UTC doesn’t make a difference. At 5:30 AM in India, it was 00:00 in UTC, the date was still December 31, and therefore the week numbers are also unchanged.
Your Calendar’s settings of first day of week and minimal days in first week follow the standard used in USA and some other countries. If instead you wanted the international standard where Monday is the first day of the week and there is a minimum of 4 days in week one, you may instantiate it with a locale of a country that uses the international standard, for example:
Calendar c = Calendar.getInstance(Locale.FRANCE);
In this case week of year will be 52 and week of month will be 4. Not 5. This is because the first three days of December are not enough to form a week, so week 1 of December begins on December 4. Then the first three days of December are in week 0.
Prefer to use java.time
All of that said, the Calendar class is long outmoded and poorly designed. I recommend you use java.time, the modern Java date and time API, instead. Specifically, the LocalDate & WeekFields classes.
For example:
LocalDate date = LocalDate.of(2017, Month.DECEMBER, 31);
System.out.println("ISO week of year " + date.get(WeekFields.ISO.weekOfWeekBasedYear()));
System.out.println("ISO week of month " + date.get(WeekFields.ISO.weekOfMonth()));
System.out.println("US week of year " + date.get(WeekFields.SUNDAY_START.weekOfWeekBasedYear()));
System.out.println("US week of month " + date.get(WeekFields.SUNDAY_START.weekOfMonth()));
Output:
ISO week of year 52
ISO week of month 4
US week of year 1
US week of month 6
The results agree with those we got from Calendar.
Link: Oracle tutorial: Date Time explaining how to use java.time.

Java Time: Get max number of weeks for particular year

I only found a solution for Joda Time.
My solution works only if the last day is not in the first week:
LocalDate.now() // or any other LocalDate
.withDayOfMonth(31)
.withMonth(12)
.get(weekFields.weekOfWeekBasedYear())
So what is the correct way in Java Time (like in Joda Time)?
This information is available directly using the java.time.* API.
The key method is rangeRefinedBy(Temporal) on TemporalField. It allows you to obtain a ValueRange object that provides the minimum and maximum values for the field, refined by the temporal object passed in.
To find out how many ISO weeks there are in the year, do the following:
LocalDate date = LocalDate.of(2015, 6, 1);
long weeksInYear = IsoFields.WEEK_OF_WEEK_BASED_YEAR.rangeRefinedBy(date).getMaximum();
System.out.println(weeksInYear);
Note that the date you pass in is used to determine the answer. So when passing in dates in early January or late December ensure you understand how the ISO week-based calendar works, and the difference between the calendar year and the week-based year.
If one wants to get the week number based on 7 days no matter when the week starts and how many days the first partial week of the year has, ChronoField.ALIGNED_WEEK_OF_YEAR might be helpful.
For example, the 1st of January 2016 based on the ISO-8601 definition (where a week starts on Monday and the first week has a minimum of 4 days) falls into week number 0, but in the aligned it is week number 1.
LocalDate date = LocalDate.of(2016, 1, 1);
int iso8601 = date.get(WeekFields.ISO.weekOfYear()); // result is 0
int aligned = date.get(ChronoField.ALIGNED_WEEK_OF_YEAR); // result is 1
It seems that when the last day is in the first week, you don't want to get 1 as an answer but 52/3/4, in which case you may be looking for:
LocalDate.of(2017, 12, 31).get(WeekFields.ISO.weekOfYear());
There are several ways to define week numbers - if that doesn't do what you want you need to clarify which method you want to use.
The correct and best solution is given by #JodaStephen. Here are some alternatives anyways.
December, 28th is always in the last week of a year, because the remaining three days after can not form a major part of another week:
int weeks = LocalDate.of(2017, 12, 28).get(WeekFields.ISO.weekOfYear());
A year has 53 weeks if it starts or ends with a thursday:
Year year = Year.of(2017);
DayOfWeek firstDay = year.atDay(1).getDayOfWeek();
DayOfWeek lastDay = year.atDay(year.length()).getDayOfWeek();
int weeks = firstDay == DayOfWeek.THURSDAY || lastDay == DayOfWeek.THURSDAY ? 53 : 52;
And finally this will give you the "week number" of the last day of year. It's 53 also in cases where the last week's number is 52 iff the major part of the last day's week lies in the next year (the week is claimed by the next year).
// This will not give the correct number of weeks for a given year
Year year = Year.of(2018);
year.atDay(year.length()).get(WeekFields.ISO.weekOfYear()); // 53
That's what you actually did.

Java SimpleDateFormat shifts Date by one year [duplicate]

This question already has answers here:
Y returns 2012 while y returns 2011 in SimpleDateFormat
(5 answers)
Closed 7 years ago.
I'm getting very weird results, which I can not understand.
public class Test {
private static DateFormat df = new SimpleDateFormat("dd.MM.YYYY HH:mm");
public static void main(String[] args) {
Date d = new Date(1356912000000L);
System.out.println(d);
System.out.println(df.format(d));
}
}
Gives the output:
Mon Dec 31 01:00:00 CET 2012
31.12.2013 01:00
I assume that this might be some issues with locales, but that's a shift by a whole year ! May anyone explain why it performs this way ?
YYYY is the week-year, not the calendar year. You want yyyy instead. Here's Java's relevant details:
Week Of Year and Week Year
Values calculated for the WEEK_OF_YEAR field range from 1 to 53. The
first week of a calendar year is the earliest seven day period
starting on getFirstDayOfWeek() that contains at least
getMinimalDaysInFirstWeek() days from that year. It thus depends on
the values of getMinimalDaysInFirstWeek(), getFirstDayOfWeek(), and
the day of the week of January 1. Weeks between week 1 of one year and
week 1 of the following year (exclusive) are numbered sequentially
from 2 to 52 or 53 (except for year(s) involved in the
Julian-Gregorian transition).
The getFirstDayOfWeek() and getMinimalDaysInFirstWeek() values are
initialized using locale-dependent resources when constructing a
GregorianCalendar. The week determination is compatible with the ISO
8601 standard when getFirstDayOfWeek() is MONDAY and
getMinimalDaysInFirstWeek() is 4, which values are used in locales
where the standard is preferred. These values can explicitly be set by
calling setFirstDayOfWeek() and setMinimalDaysInFirstWeek().
A week year is in sync with a WEEK_OF_YEAR cycle. All weeks between
the first and last weeks (inclusive) have the same week year value.
Therefore, the first and last days of a week year may have different
calendar year values.
For example, January 1, 1998 is a Thursday. If getFirstDayOfWeek() is
MONDAY and getMinimalDaysInFirstWeek() is 4 (ISO 8601 standard
compatible setting), then week 1 of 1998 starts on December 29, 1997,
and ends on January 4, 1998. The week year is 1998 for the last three
days of calendar year 1997. If, however, getFirstDayOfWeek() is
SUNDAY, then week 1 of 1998 starts on January 4, 1998, and ends on
January 10, 1998; the first three days of 1998 then are part of week
53 of 1997 and their week year is 1997.
Instead of:
"dd.MM.YYYY HH:mm"
Use:
"dd.MM.yyyy HH:mm"

Categories