java.util.calendar behaving strange - java

So, i found the java.util.Calendar, and tried to use it for a android project i'm working on.
I do not understand at all how Calendar.DAY_OF_WEEK can return 7, when it's Thursday?
And now when it's August Calendar.WEEK_OF_YEAR returns 4, which doesn't make any sense at all!
I have tried GregorianCalendar too, and it gives exactly the same results.
Tried to find any documentation about how they count, but i can't find anything.
Seems like there is something very obvious, but which i just cannot find out what it is!
The code i wrote is here:
// Get if daily or weekly
boolean daily;
daily = getPrefs.getBoolean("checkbox_daily", false);
String day = "0";
if (daily){
switch(GregorianCalendar.DAY_OF_WEEK){
case GregorianCalendar.MONDAY:
Do_stuff();
break;
case GregorianCalendar.TUESDAY:
Do_stuff();
break;
case GregorianCalendar.WEDNESDAY:
Do_stuff();
break;
case GregorianCalendar.THURSDAY:
Do_stuff();
break;
case GregorianCalendar.FRIDAY:
Do_stuff();
break;
}
}

GregorianCalendar.DAY_OF_WEEK is constant,
you need calendarInstance.get(GregorianCalendar.DAY_OF_WEEK);

From java.util.Calendar docs:
Calendar defines a locale-specific seven day week using two
parameters: the first day of the week and the minimal days in first
week (from 1 to 7). These numbers are taken from the locale resource
data when a Calendar is constructed. They may also be specified
explicitly through the methods for setting their values.
When setting or getting the WEEK_OF_MONTH or WEEK_OF_YEAR fields,
Calendar must determine the first week of the month or year as a
reference point. The first week of a month or year is defined as the
earliest seven day period beginning on getFirstDayOfWeek() and
containing at least getMinimalDaysInFirstWeek() days of that month or
year. Weeks numbered ..., -1, 0 precede the first week; weeks numbered
2, 3,... follow it. Note that the normalized numbering returned by
get() may be different. For example, a specific Calendar subclass may
designate the week before week 1 of a year as week n of the previous
year.

Related

Calendar#getActualMaximum(Calendar.WEEK_OF_YEAR) in Java 8 (java.time package) [duplicate]

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 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.

How to Map dates by their week in Java?

I had a list of objects and want to map them by their week numbers.
I've looked at using something like
private static int getWeekOfYear(LocalDate date) {
WeekFields wf = WeekFields.of(Locale.getDefault());
return date.get(wf.weekOfYear());
}
The issue is that I don't want to do this by the week number in a year.
I want to have a Map<Integer, List<DTO>> where the Integers will be 1, 2, 3, ...
I had sorted the original List<DTO> by date and then I can get the first DTO.getDate() to determine when week 1 begins.
My problem is then iterating over the DTO's and determining which week number each one will be in. I feel like I'll have to find the day of the week, then work out how many days until the start of the next week e.g. if the first date is Wednesday, then week 2 will start in 5 days and then each subsequent week will be a further 7 days.
I'm really struggling to find a nice way of writing this. So am wondering if anyone can think of a good way of creating this Map?
Thanks
Basically you want to look into the new Java8 date/time APIs when doing such computations on date.
And then please note: are you sure you want to use a Map here?
If I get your input right, you say that the keys will run 1, 2, 3, ... anyway? So - when you know that the keys will just be a sequence of numbers, why not use a list then?
Another alternative would be to use a TreeSet and a custom compartor. If you use the comparator to sort your DTO objects based on their date, the TreeSet will automatically put them into the correct order!
WeekField has a overloaded method to specify the start day of the week and number of days in first week.
Since the DTO List is already sorted and the first day of week would be the starting day and 7 days from that day would be the next week.
List<DTO> dtos = ...// sorted
LocalDate firstDate = dtos.get(0).getDate();
WeekFields weekFields = WeekFields.of(firstDate.getDayOfWeek(), 7); // to override the default start day and no of days in first week
Map<Integer, List<DTO>> map = dtos.stream().collect(Collectors.groupingBy(dto -> dto.getDate().get(weekFields.weekOfYear())));
Try JodaTime's week of year format: http://joda-time.sourceforge.net/field.html#weekyear
A week based year is one where dates are expressed as a day of week,
week number and year (week based). The following description is of the
ISO8601 standard used by implementations of this method in this
library. Weeks run from 1 to 52-53 in a week based year. The first day
of the week is defined as Monday and given the value 1. The first week
of a year is defined as the first week that has at least four days in
the year. As a result of this definition, week 1 may extend into the
previous year, and week 52/53 may extend into the following year.
Hence the need for the year of weekyear field. For example, 2003-01-01
was a Wednesday. This means that five days, Wednesday to Sunday, of
that week are in 2003. Thus the whole week is considered to be the
first week of 2003. Since all weeks start on Monday, the first week of
2003 started on 2002-12-30, ie. in 2002. The week based year has a
specific text format.
2002-12-30 (Monday 30th December 2002) would be represented as 2003-W01-1
2003-01-01 (Wednesday 1st January 2003) would be represented as 2003-W01-3.
What you have to do, is find the first day of the week of the first date, and create the map using this date as reference :
private static Map<Long, List<DTO>> mapByWeek(final List<DTO> dtos) {
if (dtos.isEmpty())
return Collections.emptyMap();
// find the first day of first week
final LocalDate referenceDate = dtos.stream().sorted(Comparator.comparing(DTO::getDate)).findFirst()
.map(dto -> dto.getDate().with(WeekFields.of(Locale.getDefault()).dayOfWeek(), 1)).get();
// group by number of weeks of difference with the reference date
return dtos.stream().collect(Collectors.groupingBy(dto -> ChronoUnit.WEEKS.between(referenceDate, dto.getDate()) + 1));
}

Calendar not working fine

I am a 3 month old java student. For one of my module I tried to make first day of week as tuesday(so that a real friday should now be at index 3) but it didn't show expected result.
I am inputting day through scanner.
Below is the concerned piece of code and output:
Calendar c= Calendar.getInstance();
c.setFirstDayOfWeek(Calendar.TUESDAY);
c.setTime(date);
int dayOfWeek=c.get(Calendar.DAY_OF_WEEK);
System.out.println(dayOfWeek);
Output:
Enter the date(dd/mm/yyyy):
03/07/2014
6
Don't know where I am wrong. Tried a lot googling around and even set minimalDAysOfFirstWeek but nothing working out. What i want is 03/07/2014 to be shown as index 3. How to achieve so?
I think you've misunderstood the purpose of setFirstDayOfWeek.
That doesn't change c.get(Calendar.DAY_OF_WEEK) works at all - it changes the result of calling c.get(Calendar.WEEK_OF_MONTH) and c.get(Calendar.WEEK_OF_YEAR), as per the documentation:
When setting or getting the WEEK_OF_MONTH or WEEK_OF_YEAR fields, Calendar must determine the first week of the month or year as a reference point. The first week of a month or year is defined as the earliest seven day period beginning on getFirstDayOfWeek() and containing at least getMinimalDaysInFirstWeek() days of that month or year.
In other words, Sunday is always Sunday... but whether Sunday June 10th is in the same week as Monday June 11th or not depends on what is considered to be the first day of the week.
switch (c.get(Calendar.DAY_OF_WEEK)) {
case Calendar.TUESDAY:
return 0;
case Calendar.WEDNESDAY:
return 1;
// And so on...
default:
break;
}

Help with Java Calendar -- it is giving some strange output

I'm newish to Java and am trying to do somethings with dates. First I started using the Date class, which I found out was mostly deprecated so I switched over to Calendar.
Now I am getting weird values. for example the Month value for December is 0, not 12. And on those Calendars where it is giving me 0 for December it is also moving the year ahead one year.
It's weird!
What am I missing?
Thanks for your help.
-GG
EDIT FOR AN EXAMPLE:
So I am reading some line sin from a file such as this:
Johnny Graham H F 12-2-1973 Black
I parse it, and then for the Calendar I set:
int year = Integer.parseInt(stringVersionOfYear); // this value is 1973
Then later when I go to get the year back with a line like this:
calendar.get(Calendar.YEAR)
the value is 1974... And the month is 0 for
cal.get(Calendar.MONTH)
EDIT 2:
I am creating the Calendar like this:
Calendar outputCalendar = Calendar.getInstance();
outputCalendar.set(year, month, day);
The java.util.Date and Calendar classes are poorly designed (eg, the first day in a month is day 1 but the first month in a year is month 0). Many projects use the Joda Time package instead.
Months values are 0 thru 11; set a month to 12 and the date gets "normalized", incrementing the year by one and setting the month to 0. This makes it easy to "add a month" without having to worry about handling the overflow at year end.
EDIT: January=0, February=1,... December=11. When you set the month value to 12 you were asking for the 13th month, which got normalized to the first month of the following year.
Note that this normalization process happens in general -- Try to set the date to December 32nd and you'll get back January 1 of the following year. This means it's important to be careful when modifying individual fields of a Calendar object. If you create a default Calendar on, say, January 31st and then want to modify it to contain, say February 5th, the order in which you set the fields is important. If you change the month first you'll be creating February 31st, which will get normalized to March 2nd or 3rd (depending on the leap year) and then when you set the day to 5 the result is March 5th, not February 5th. You have the opposite problem in other cases, such as starting from any date in February and modifying to the 30th or 31st of any other month. In that case doing the month first results in the same type of problem.
The only safe way to modify a date is to use a method that sets all three values simultaneously, such as the set(int,int,int) method.
See this line?
outputCalendar.set(year, month, day);
Just change it like this:
outputCalendar.set(year, month - 1, day);
and then when you want to get the month, don't use this:
cal.get(Calendar.MONTH)
instead, use this:
(1+(cal.get(Calendar.MONTH)))
It's a pain, but it will fix the problem (I think).
The main piece of advice I have for you is: read the API! Calendar is indeed not the pinnacle of intuitive API design, but it is definitely usable if you take the time to read the javadoc. Learn the difference between .add and .roll. Check out what happens when you set a year (1973) into a Calendar initialized with the current date (default Calendar.getInstance).
Whining about API is all fine (we all do it), but in the end to find solutions start off by reading what the authors provided to you before asking relatively obtuse questions on the Internet.

Categories