I am working on a project and need to generate recurrences for a date range using iCal4J library.
Basically it is a simple RRule to repeat weekly, every friday for the duration of six months.
This is what I have:
Recur recur = new Recur("FREQ=WEEKLY;INTERVAL=1;BYDAY=FR;WKST=MO;UNTIL=20170428T003000Z;");
DateTime startDate = new DateTime("20160727T0030000Z");
Date endDate = recur.getUntil();
DateTime baseDate = new DateTime("20160727T003000Z");
DateList dateList = recur.getDates(baseDate, startDate, endDate, Value.DATE_TIME);
This generates weekly meetings every friday at half midnight, however the last meeting should be on the 27/01/2017 but instead it is 20/01/2017.
One meeting gets taken out.
Ps this only occurs within this date range (maybe something to do with Britsh Summer Time BST), however it is set to be UTC therefore it should not matter right?
Then if I change the UNTIL property from the recurrence rule to be 21-01-2017 at 23:59:59 then it gets picked up.
Any suggestions?
Regards
Try it out : Here is an example for my recurrence rule for same.
If my start date is 10/08/2016 and date is 10/12/2016 then this will
create recurring dates for all friday coming between these two dates.
Weekly Recurrence Rule is
RRULE:FREQ=WEEKLY;BYDAY=FR;INTERVAL=1;UNTIL=20161218T000000Z
RRULE:FREQ=WEEKLY;BYDAY=<Day of week>;INTERVAL=<Every month/with some interval>;UNTIL=<Until Date>
So as per this your rule will be like : "RRULE:FREQ=WEEKLY;BYDAY=FR;INTERVAL=1;UNTIL=20170428T003000Z"
Related
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));
}
I want to get today's day and a date which is one year after today. For example, if today is 2015-9-18, next year is 2016-9-18.
I would like to use Java LocalDate.
The current date is simply retrieved with:
LocalDate now = LocalDate.now();
Then, you can add one year to this date, using the method plusYears(years):
LocalDate oneYearAfter = now.plusYears(1);
LocalDate contains various methods to ease the task of adding or subtracting a temporal amount (like plusDays, plusMonths; the most general being plus(amount, unit) adding the amount given for the specified unit of time).
I need to create a new Java Date based on two strings provided by a user: a date (e.g. "1.1.2015"), and a time of day (e.g. "23:00"). First the user enters the date, which is sent to the server and parsed into a Date (time of day is set to midnight in the user's time zone). After this, the user enters the time of day, which is sent to the server, and a new Date needs to be created, combining the date from the first Date instance and time of day from the new user input.
Example: Say the server's time zone is UTC, and the user's time zone is UTC-2. The user enters "1.1.2015" into the date field, which is interpreted in the server as 2:00 1.1.2015 UTC (1st of January at 2:00 AM in UTC, which is midnight in the user's time zone). The user then enters "23:00" into the time field (24-hour clock). This needs to be interpreted in the server as 1:00 2.1.2015 UTC (2nd of January at 1:00 AM).
We use Apache Commons FastDateFormat for transforming strings to Dates and vice versa, and Joda Time for date manipulation. The result needs to be a plain old Java Date. I've tried to combine the existing Date instance and the time of day input from the user like this:
Date datePart= ...; // The date parsed from the first user input
FastDateFormat timeFormat = ...;
DateTimeZone userTimeZone = DateTimeZone.forTimeZone(timeFormat.getTimeZone());
String userTimeInput = ...; // The time of day from the user
MutableDateTime dateTime = new MutableDateTime(datePart, DateTimeZone.UTC);
Date newTime = timeFormat.parse(userTimeInput);
dateTime.setTime(new DateTime(newTime, DateTimeZone.UTC));
// Determine if the date part needs to be changed due to time zone adjustment
long timeZoneOffset = userTimeZone.getOffset(dateTime);
long newMillisOfDay = dateTime.getMillisOfDay();
if (newMillisOfDay + timeZoneOffset > 24 * 60 * 60 * 1000) {
dateTime.addDays(-1);
} else if (newMillisOfDay + timeZoneOffset < 0) {
dateTime.addDays(1);
}
Date newServerDate = dateTime.toDate();
Changing the time of day of an existing Date like this is a bit problematic. The above doesn't work; if the user changes the time of day multiple times, the +/-1 day adjustment is potentially made every time. Also, the above code doesn't take DST into account. If datePart is in DST, the times entered by our example user should be treated as being in UTC-1. When using FastDateFormat and only parsing the time of day, the date is set to the epoch, meaning that the time entered by the user will always be treated as being in UTC-2. This will cause a one hour offset in the result.
How to adjust the Date in the server based on the given time of day and properly take the time zone and DST into account?
I solved this by using the suggestions by Jon in the comments. I still have to end up with a Date, so I couldn't start using Joda Time for everything. I did however move away from FastDateFormat and MutableDateTime for this particular use case. Thanks for the tips! The solution looks like this:
Date datePart= ...; // The date parsed from the first user input
String userTimeInput = ...; // The time of day from the user
Locale userLocale = ...;
DateTimeZone userTimeZone = ...;
DateTime dateInUserTimeZone = new DateTime(datePart, userTimeZone);
DateTimeFormatter formatter = DateTimeFormat.shortTime().withLocale(userLocale);
LocalTime time = formatter.parseLocalTime(userTimeInput);
Date newDate = dateInUserTimeZone.withTime(time.getHourOfDay(), time.getMinuteOfHour(),
time.getSecondOfMinute(), time.getMillisOfSecond()).toDate();
What is the difference between the two dates below in practice?
Date date = new Date();
Date date = Calendar.getInstance().getTime();
What I understand is that new Date() is a UTC/GMT based date while calendar's getTime() is based on TimeZone & System time. Am I right? Do I miss something still?
Moreover, if my above understanding is correct, can I say that the end results of the following two functions are exactly the same ?
1.
public String getDate1(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//I set the time zone & pass the new Date()
sdf.setTimeZone(TimeZone.getDefault());
return sdf.format(new Date());
}
2.
public String getDate2(){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//I didn't set the time zone because I think calendar instance will handle timezone change
return sdf.format(Calendar.getInstance().getTime());
}
I appreciate if you could point out where I understand wrongly & explain to me clearly. Because I feel this thing is confused to me. Thanks!
Practical info about Java Calendar and Date
If you want to operate with different dates in your Java program you will use Java Calendar class.
I will try to give you some overview of not widely known facts about Java Calendar and Date classes, working code examples, which you can try right away.
The basic information about Calendar class is provided by Java API. The Calendar class is about days, months and years. One could ask: is not Date class about the same? Not exactly...
What is difference between Java Date and Calendar classes?
The difference between Date and Calendar is that Date class operates with specific instant in time and Calendar operates with difference between two dates. The Calendar class gives you possibility for converting between a specific instant in time and a set of calendar fields such as HOUR, YEAR, MONTH, DAY_OF_MONTH. You can also manipulate with the calendar fields, for example getting the date of your grandmother birthday :).
I would like to point some things about Calendar and Date which you should know and which are not obvious...
Leap seconds.
Years, months, dates and hours are in "normal" range like:
A year y - 1900.
A month from 0 to 11
A date (day of month) from 1 to 31 in the usual manner. calendar leap seconds
An hour 0 to 23.
A minute from 0 to 59 in the usual manner.
But, attention!! A second is represented by an integer from 0 to 61. Looks strange - 61 second, but do not forget about leap second. About once every year or two there is an extra second, called a "leap second." The leap second is always added as the last second of the day, and always on December 31 or June 30. For example, the last minute of the year 1995 was 61 seconds long, thanks to an added leap second.
Lenient fields.
Another funny feature is lenient and non-lenient fields in calendar. What is that? Example:
32 January 2006. Actually if you set your calendar lenient it will be 1 February 2006 and no problem for your program :). If it is non-lenient ArrayIndexOutOfBoundsException exception will be thrown.
Another question is 00:00 end or beginning of day? Is 00:00 A.M. or P.M.? Are midnight and noon A.M. or P.M?
Answer: 23:59 is the last minute of the day and 00:00 is the first minute of the next day. Midnight belongs to "am", and noon belongs to "pm", so on the same day, 12:00 am (midnight) < 12:01 am, and 12:00 pm (noon) < 12:01 pm.
And probably last question: what is epoch? and why this Epoch since January 1, 1970 00:00:00.000 GMT.
Actually it is Unix time, or POSIX time, is a system for describing points in time: it is the number of seconds after 00:00:00 UTC, January 1, 1970.
Wait, one question more!
"If we use the time which is counted since Epoch, how can I know which years had leap seconds and which not?"
Answer: To make life easier leap seconds are not counted. Java Date class takes actual time from OS and most of modern computers can not use leap seconds, their's internal clocks are not so precised. That's why periodical time synchronization is required.
There is no difference between at all between those two dates. (The second one is of course a bit wasteful in allocating a Calendar object that you don't use.)
An instance of java.util.Date is an absolute point in time. It has no knowledge of time zones. Setting the Default timezone on the SimpleDateFormat similarly does nothing, it uses the default by.... default!
To try to explain in different terms, the java.util.Date for
10:49 pm Dec 19, 2013 UTC
And
5:49 pm Dec 19, 2013 US Eastern Time
Is exactly the same object. The exact same java.util.Date represents both of those human-readable representations of time. The human-readable considerations only come into play when you use the formatter to turn it back and forth. (Hence why you set the timezone on the formatter, not on the date, date has no knowledge of what a timezone means.)
In 2022, you MUST use java.time classes and you can refer here to know almost everything that needs to be known about time. But if you are using Java versions older than 8, or if you are curious, read on for some high-level overview.
1. Date date = new Date(); //Thu Mar 24 04:15:37 GMT 2022
2. Date date = Calendar.getInstance().getTime(); //Thu Mar 24 04:15:37 GMT 2022
Date(Does not have a notion of timezone, and is mutable, i.e not thread-safe)
Date is sufficient if you need only a current timestamp in your
application, and you do not need to operate on dates, e.g., one-week
later. You can further use SimpleDateFormat to control the date/time
display format.
Calendar(Abstract class, concrete implementation is GregorianCalendar)
Calendar provides internationalization support. Looking into the
source code reveals that: getInstance() returns a GregorianCalendar
instance for all locales, (except BuddhistCalendar for Thai ("th_TH")
and JapaneseImperialCalendar for Japanese ("ja_JP")).
Trivia
If you look at the Date java documentation, you will see many deprecated methods and the note:As of JDK version 1.1, replaced by Calendar.XXX. This means Calendar was a failed attempt to fix the issues that Date class had.
Bonus
You might want to watch this to get some more insights of Date vs Calendar
I would like to know exactly how many months and days(possibly years) some older date is from today. Is there a method to do that?
I know how to get the difference of the months, I know how to get the difference in days. But I am unable to get the months and the days.
Ex:
old = '2013-03-04'
now = '2013-04-17'
so the result im looking for is something like 1 month(s) and 13* day(s)
*maybe its 12 im not every sure.
This can be done by using Period in JodaTime.
For example,
LocalDate old = new LocalDate(2013, 3, 4);
LocalDate now = new LocalDate(2013, 4, 17);
Period p = new Period(old, now, PeriodType.yearMonthDay());
To get the months, use p.getMonths(), to get the days p.getDays().
The result of the example is 1 month, 13 days.
Yes, see the documentation of intervals:
Intervals
An interval in Joda-Time represents an interval of time from one
instant to another instant. Both instants are fully specified instants
in the datetime continuum, complete with time zone.
Intervals are implemented as half-open, which is to say that the start
instant is inclusive but the end instant is exclusive. The end is
always greater than or equal to the start. Both end-points are
restricted to having the same chronology and the same time zone.
Two implementations are provided, Interval and MutableInterval, both
are specializations of ReadableInterval.