How does changing DAY_OF_WEEK in java.util.Calendar work? - java

I am trying to change DayofWeek in Calendar but doesnt appear to be working as I expect. Here is an example. I set calendar time to a Friday time, but when I set Calendar.DAY_OF_WEEK to Calendar.SUNDAY, it is moving forward to next week. Since Calendar.SUNDAY is first day of week by default, shouldn't it move the time back to beginning of current week?
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class GenericWeekdayOpenFunction implements TimePeriodFunction {
public static void main(String[] args) {
// Nov 8 is Friday
long time = DateUtilities.newDateTimeAsMillis(2013, 11, 8, 10, 00, 00);
System.out.println(DateUtilities.formatGmtDatetime(time));
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
calendar.setTimeInMillis(time);
// move day of week to Sunday, expect date to be Nov 3
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(DateUtilities.formatGmtDatetime(calendar.getTimeInMillis())); // wrong
// move day of week to Friday, expect date to be Nov 8
calendar.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(DateUtilities.formatGmtDatetime(calendar.getTimeInMillis()));
}
}
Output:
08-11-2013 10:00:00.000
10-11-2013 10:00:00.000
08-11-2013 10:00:00.000

Your scenario working fine with basic Calendar class usage:
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
Date d = new Date(113, 10, 8, 10, 0, 0);
c.setTimeInMillis(d.getTime());
System.out.println(c.getTime());
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(c.getTime());
c.set(Calendar.DAY_OF_WEEK, Calendar.FRIDAY);
System.out.println(c.getTime());
Output:
Fri Nov 08 10:00:00 IST 2013
Sun Nov 03 10:00:00 IST 2013
Fri Nov 08 10:00:00 IST 2013
Note that Date(113, 10, 8, 10, 0, 0); is used only for quick check, it is deprecated though. Trying for any other combination also works fine. Can you just try using basic Calendar API and print dates ie
Calendar c = new GregorianCalendar(TimeZone.getTimeZone("GMT"));
System.out.println(c.getTime());//current day
c.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
System.out.println(c.getTime());
second date should go back to previous sunday not upcoming one. If it's working for you then DateUtilities implementation may be doubtful.

I think that the method set(int field, int value)
Works approaching to the nearest day (not to the DAY_OF_WEEK of the same week).
But you can use the function add(int field, int amount) in this case add(Calendar.DATE, -5) to do that.

Related

Calendar Sunday to Sunday

I'm trying to get flights for 8 days starting from Sunday to the next Sunday.
The way I have implemented it now is by displaying the 7 days starting the selected date from my form.
// set up calendar for sunday
Calendar sunday = Calendar.getInstance();
sunday.setTime(form.getDate());
sunday.add(Calendar.DAY_OF_WEEK, -1 * (sunday.get(Calendar.DAY_OF_WEEK) - 1));
//set up calendar for next saturday
Calendar saturday = Calendar.getInstance();
saturday.setTime(sunday.getTime());
saturday.add(Calendar.DAY_OF_WEEK, 7);
Since the max of DAY_OF_WEEK is 7, what do I need to use instead?
I tried changing this line:
saturday.add(Calendar.DAY_OF_WEEK, 7);
to the following one:
saturday.add(Calendar.DATE, 8);
I already tried couple changes but no luck.
Any advice?
Try using Calendar.DAY_OF_YEAR.
import java.text.*;
import java.util.*;
DateFormat dateFormat = new SimpleDateFormat("EEE, MMM dd, yyyy hh:mm:ss a z");
Calendar sunday = new GregorianCalendar();
sunday.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY); // Set day of week to Sunday.
System.out.println(dateFormat.format(sunday.getTime()));
sunday.add(Calendar.DAY_OF_YEAR, 7); // Add seven days.
System.out.println(dateFormat.format(sunday.getTime()));
Output
Sun, Dec 04, 2016 11:47:32 PM EST
Sun, Dec 11, 2016 11:47:32 PM EST
You can create new calendar objects without modifying the existing one, by making a copy.
import java.text.*;
import java.util.*;
public class CalendarUtils {
public static void main(String[] args) {
Calendar sunday = CalendarUtils.getThisSundaysDate();
Calendar saturday = CalendarUtils.daysFrom(sunday, 6);
CalendarUtils.printDates(sunday, saturday);
}
public static Calendar getThisSundaysDate() {
Calendar sunday = new GregorianCalendar();
sunday.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
return sunday;
}
public static Calendar daysFrom(Calendar cal, int days) {
Calendar newCal = copyCalendar(cal);
newCal.add(Calendar.DAY_OF_YEAR, days);
return newCal;
}
public static Calendar copyCalendar(Calendar cal) {
Calendar copy = new GregorianCalendar();
copy.setTime(cal.getTime());
return copy;
}
public static void printDates(Calendar from, Calendar to) {
DateFormat dateFormat = new SimpleDateFormat("EEE, MMMM dd, yyyy hh:mm:ss a z");
System.out.println(dateFormat.format(from.getTime()));
System.out.println(dateFormat.format(to.getTime()));
}
}
If you're using Java 8, you should use the new java.time classes. In this case, you'd want to use the LocalDate class, and the TemporalAdjusters class, with it's previous(DayOfWeek) method.
Alternatively, use the previousOrSame(DayOfWeek), depending on what should happen if the reference date is a Sunday.
Example, using today as the reference date:
LocalDate refDate = LocalDate.now();
LocalDate prevSunday = refDate.with(TemporalAdjusters.previous(DayOfWeek.SUNDAY));
LocalDate nextSunday = prevSunday.plusDays(7);
DateTimeFormatter fmt = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
System.out.println("Ref. Date: " + refDate.format(fmt));
System.out.println("Prev. Sunday: " + prevSunday.format(fmt));
System.out.println("Next. Sunday: " + nextSunday.format(fmt));
Output
Ref. Date: Monday, December 5, 2016
Prev. Sunday: Sunday, December 4, 2016
Next. Sunday: Sunday, December 11, 2016

Get third friday of a month

I develop a local calendar for my application. but there is an issue with monthly repeat event (day of week).
When i create an event starting on 16-9-2016(16 SEP 2016 FRIDAY) and repeating Third Friday of each month. but next month it create on second
Friday 14-10-2016 (This is the issue). next month it will be on third Friday.
my code is
public Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
calendar.set(Calendar.WEEK_OF_MONTH, week);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
return calendar.getTime();
}
I know the issue. but i don`t know how to fix it.. is there any way to fix it ?
You code seems to be working completely fine, there is nothing that is going wrong from what I can see, it may be that your parameters are wrong.
It is important to note that MONTH and DAY are 0-based so, 0 = January and 0 = Sunday so your parameters for getting the third friday should look like the following:
nthWeekdayOfMonth(6, 9, 2016, 3, TimeZone.getTimeZone("Europe/London"));
Which returns the following output:
Fri Oct 21 11:06:33 BST 2016
To break it down:
Day of week is 6, because Sunday = 0.
Month is 9 - i.e. October
Year is normal - 2016
Week is NOT 0-based so 3rd week will be index 3
TimeZone as normal
Please see the Calendar documentation for reference.
EDIT
So for some reason, it works on my machine but it doesn't on others; I don't know what the issue could be with that but using DAY_OF_WEEK_IN_MONTH seems to be a better option for this:
public static Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
//calendar.set(Calendar.WEEK_OF_MONTH, week);
calendar.set(Calendar.DAY_OF_WEEK_IN_MONTH, week);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.YEAR, year);
return calendar.getTime();
}
I usually use GregorianCalendar but Calendar should work just fine.
This should (hopefully) work for the most part, I've tested it on other machines and ideone.
I could propose next decision:
public Date nthWeekdayOfMonth(int dayOfWeek, int month, int year, int week, TimeZone timeZone) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(timeZone);
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DAY_OF_MONTH, 1);
// add +1 to week if first weekday of mounth > dayOfWeek
int localWeek = week;
if (calendar.get(calendar.DAY_OF_WEEK) > dayOfWeek) {
localWeek++;
}
calendar.set(Calendar.WEEK_OF_MONTH, localWeek);
calendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
return calendar.getTime();
}
for:
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.SEPTEMBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.OCTOBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
System.out.println(nthWeekdayOfMonth(Calendar.FRIDAY, Calendar.NOVEMBER, 2016, 3, TimeZone.getTimeZone("Europe/London")));
it returns:
Fri Sep 16 19:41:23 YEKT 2016
Fri Oct 21 19:41:23 YEKT 2016
Fri Nov 18 20:41:23 YEKT 2016
Java 8
LocalDate thirdFriday = java.time.LocalDate.now()
.with(TemporalAdjusters.firstDayOfMonth())
.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY))
.plusDays(14)
java.time
java.time, the modern Java date and time API, has a built-in adjuster for that:
public LocalDate nthWeekdayOfMonth(DayOfWeek dayOfWeek, Month month, int year, int week) {
return LocalDate.of(year, month, 15)
.with(TemporalAdjusters.dayOfWeekInMonth(week, dayOfWeek));
}
Try it out:
System.out.println(nthWeekdayOfMonth(DayOfWeek.FRIDAY, Month.OCTOBER, 2016, 3));
Output:
2016-10-21
Please also note that the arguments that I pass to the method are much more telling.
Link: Oracle tutorial: Date Time explaining how to use java.time.
This is a functioning Java 8 implementation. The example from KayV did not work for September 2017, but it helped me to head in the right direction.
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class OptionExpirationDates {
public static void main(String[] args) {
LocalDate startDate = LocalDate.of(2017, Month.FEBRUARY, 15);
List<LocalDate> optionExDates = optionExpirationDates(startDate, 20);
for (LocalDate temp : optionExDates) {
System.out.println(temp);
}
}
public static List<LocalDate> optionExpirationDates(LocalDate startDate, int limit) {
return Stream.iterate(startDate, date -> date.plusDays(1))
.map(LocalDate -> LocalDate.with(TemporalAdjusters.firstDayOfMonth()).minusDays(1)
.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)).plusWeeks(2))
.distinct()
.limit(limit)
.collect(Collectors.toList());
}
}
Perhaps we should also mention that this code is to calculate an option expiration date, so that the search engine can pick it up.
Java 8 way of doing this is as follows:
LocalDate thirdFriday = LocalDate
.now()
.with(lastDayOfMonth())
.with(previous(DayOfWeek.FRIDAY)).minusDays(7);
To take a different approach. If the first day of the month is a Saturday, then the third Friday is the 21st of that month. Extend this for the seven possible days:
Saturday 1st -> Friday 21st.
Sunday 1st -> Friday 20th
Monday 1st -> Friday 19th
Tuesday 1st -> Friday 18th
Wednesday 1st -> Friday 17th
Thursday 1st -> Friday 16th
Friday 1st -> Friday 15th
You just need to check what day of the week the first of the month is.
Below function can be used to calculate third friday of month using joda time. The function is verbose for sake of clarity on logic.
public static DateTime thirdFridayOfMonth(int year, int month) {
DateTime firstDayOfMonth = new DateTime(year, month, 1, 0, 0);
MutableDateTime mFirstDayOfMonth = new MutableDateTime(firstDayOfMonth);
//Now calculate days to 1st friday from 1st day of month
int daysToFirstFridayOfMonth = mFirstDayOfMonth.dayOfWeek().get() <= 5 ? (5 - mFirstDayofMonth.dayOfWeek().get()) : (7 - mFirstDayofMonth.dayOfWeek().get() + 5);
//move to first 1st friday of month
mFirstDayOfMonth.addDays(daysToFirstFridayOfMonth);
//move to 3rd friday of month
mFirstDayOfMonth.addWeeks(2);
return mFirstDayOfMonth.toDateTime();
}
with Java LocalDateTime
LocalDateTime firstDayOfMonth = LocalDateTime.of(year, Month.of(month), 1, 0, 0);
// Returns 1-7 (NOT 0-6)
int firstDayValue = firstDayOfMonth.getDayOfWeek().getValue();
int thirdFriday = 20 + firstDayValue / 6 * 7 - firstDayValue;
return LocalDateTime.of(year, Month.of(month), thirdFriday, 0, 0);

Using GregorianCalendar to get weeks

I'm looking to utilize GregorianCalendar to do some logic based on days. Is there any way to see if 2 dates are in the same week? I've tried using get(Calendar.WEEK_OF_YEAR), and this has the two downsides of:
1) Starting on the wrong day of the week (which seems to have a potential solution in setFirstDayOfWeek, however preliminary testing has not been successful.
2) This solution does not carry over years nicely. For example - Dec 30th, 2014 and Jan 1, 2015 should be in the same week.
Is there any solution to this that doesn't require switching libraries?
OK, since you've stated there will be a time component, I'd use something similar to #MadProgrammer's answer, but without the complexity of using an entire date range. I'd have a static method something like this.
public static Date firstOfWeek(Calendar cal) {
Calendar copy = new GregorianCalendar(
cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DATE));
copy.set(Calendar.DAY_OF_WEEK, copy.getFirstDayOfWeek());
return copy.getTime();
}
This returns a Date for the first day of the week that includes a particular Calendar. You can then check whether two calendars fall in the same week like this.
if (firstOfWeek(cal1).equals(firstOfWeek(cal2))) {
...
}
You question basically boils down to determining if a given date falls within a given date range (ie a week).
The idea behind this is basically one of the two date's acts as the anchor, from which we calculate the date range (start of week to end of week) and then determine if the other date falls within that range.
So, first, we need to calculate the date range, something like...
Calendar cal = Calendar.getInstance();
cal.setTime(date1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date startOfWeek = cal.getTime();
cal.add(Calendar.DATE, 6);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
Date endOfWeek = cal.getTime();
Which will give us two dates, the first starting at the "start of the week" and one 6 days later (the "end of the week"). We force the time values to the extreme of the days to ensure we can capture the fall range
Next, we need to determine if the other date is equal to or after the "start of the week" and equal to or before the "end of the week", something like...
(date2.equals(startOfWeek) || date2.after(startOfWeek)) && (date2.equals(endOfWeek) || date2.before(endOfWeek));
This could then be wrapped up in a nice little method to make calling it simpler...
public static boolean isInSameWeek(Date date1, Date date2) {
Calendar cal = Calendar.getInstance();
cal.setTime(date1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.clear(Calendar.MINUTE);
cal.clear(Calendar.SECOND);
cal.clear(Calendar.MILLISECOND);
cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek());
Date startOfWeek = cal.getTime();
cal.add(Calendar.DATE, 6);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 59);
cal.set(Calendar.SECOND, 59);
cal.set(Calendar.MILLISECOND, 999);
Date endOfWeek = cal.getTime();
System.out.println("Week starts at : " + startOfWeek);
System.out.println(" Week ends at : " + endOfWeek);
return (date2.equals(startOfWeek) || date2.after(startOfWeek)) && (date2.equals(endOfWeek) || date2.before(endOfWeek));
}
And then we can test it...
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
try {
Date date1 = sdf.parse("30/12/2014");
Date date2 = sdf.parse("1/1/2015");
System.out.println("Is in same week " + date1 + "/" + date2 + " = " + isInSameWeek(date1, date2));
System.out.println("");
date1 = sdf.parse("27/12/2014");
System.out.println("Is in same week " + date1 + "/" + date2 + " = " + isInSameWeek(date1, date2));
} catch (ParseException exp) {
exp.printStackTrace();
}
Which outputs something like...
Week starts at : Sun Dec 28 00:00:00 EST 2014
Week ends at : Sat Jan 03 23:59:59 EST 2015
Is in same week Tue Dec 30 00:00:00 EST 2014/Thu Jan 01 00:00:00 EST 2015 = true
Week starts at : Sun Dec 21 00:00:00 EST 2014
Week ends at : Sat Dec 27 23:59:59 EST 2014
Is in same week Sat Dec 27 00:00:00 EST 2014/Thu Jan 01 00:00:00 EST 2015 = false

wrong time calculating in Java

when I want to sum two dates in java it does not work:
System.out.println(date + " <---- date");
System.out.println(time + " <---- time");
System.out.println(new Date(date.getTime() + time.getTime()) + " <---- new Date(time.getTime() + date.getTime())");
leads to following output:
Wed Nov 06 00:00:00 CET 2013 <---- date
Thu Jan 01 11:51:14 CET 1970 <---- time
Wed Nov 06 10:51:14 CET 2013 <---- new Date(time.getTime() + date.getTime())
... but if i work with Calender it works!
Calendar calendar = Calendar.getInstance();
calendar.setTime(time);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int min = calendar.get(Calendar.MINUTE);
calendar.setTime(date);
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, min);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date myDate = calendar.getTime();
System.out.println(myDate);
results in
Wed Nov 06 11:51:00 CET 2013
which is correct
Can anybody explain me why?
Fundamentally, you've got problems with time zones here. The fact that you're using a java.util.Date to represent a time of day is messing you up to start with. Your time of 11:51:14 CET is actually 10:51:14 UTC, so when you add the result of calling time.getTime(), you're only adding "just under 11 hours" rather than "just under 12 hours". The use of inappropriate data types makes all this hard to work with and understand.
I'd strongly recommend using Joda Time for all of this. Then you can start with a LocalDate and LocalTime, combine them into a LocalDateTime and then work out if you want to apply a particular time zone.
Using the right data types, which mean exactly what you're trying to convey, makes a huge difference for date/time work.

End of DayLight Saving Time Issue in java

I am trying to find how DST works,for that I have written sample of code which talks about DST,I wonder why TimeZone changes at 1:00AM as per my understanding DST end 03 November 2013 at 2:00AM so at 2:00AM it should give 1:00AM then TimeZone should be chnaged, but its not like that. Can anyone help me out of this...
public static void main(String[] args) throws InterruptedException
{
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
DateFormat fmt = new SimpleDateFormat("dd-MM-yy HH:mm:ss zz");
Calendar cal = Calendar.getInstance();
cal.set(2013, 10, 03, 0, 59, 59);
System.out.println(fmt.format(cal.getTime()));
cal.set(2013, 10, 03, 1, 0, 0);
System.out.println(fmt.format(cal.getTime()));
}
Output:
03-11-13 00:59:59 PDT
03-11-13 01:00:00 PST
01:00 happens twice, once in PDT and once (an hour later) in PST.
If you tell the Calendar that it is 01:00 on a date of time change, then the class identifies that your input corresponds to 2 distinct possible times, and arbitrarily uses one of them.
#Andrew Spencer is right, 1:00 a.m. has two possibilities, and Calendar picked one of them, just not the one you were expecting. If you want to see 1:00 AM PDT, then just add a minute to 12:59 AM:
public static void main(String[] args) throws InterruptedException {
TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
DateFormat fmt = new SimpleDateFormat("dd-MM-yy HH:mm:ss zz");
Calendar cal = Calendar.getInstance();
cal.set(2013, 10, 03, 0, 59, 59);
System.out.println(fmt.format(cal.getTime()));
cal.add(Calendar.MINUTE, 1); // this will still be in PDT
System.out.println(fmt.format(cal.getTime()));
}
If I understand you correctly you wonder why 03-11-13 01:00:00 is PST? I think you explained this yourself. If 2:00 actually has to be moved to 1:00, so 1:00 is already daylight saving time, i.e. PST.

Categories

Resources