I need to get Instant time from week number of year. Now I'm using old Calendar API to calculate time:
int week = 1; // week of year
final Calendar cal = new GregorianCalendar();
cal.set(0, 1, 0, 0, 0, 0); // reset calendar
cal.set(Calendar.YEAR, Year.now().getValue());
cal.set(Calendar.WEEK_OF_YEAR, week);
cal.setTimeZone(TimeZone.getTimeZone(ZoneOffset.UTC));
final Instant start = cal.getTime().toInstant();
final Instant end = start.plus(Period.ofWeeks(1));
Is it possible to get Instant from week of year using new Java time API (java.time package)?
WeekFields wf = WeekFields.of(Locale.getDefault());
int week = 1; // week of year
LocalDate startDate = LocalDate.now(ZoneOffset.UTC)
.with(wf.weekOfWeekBasedYear(), week)
.with(wf.dayOfWeek(), 1);
Instant startInstant = startDate.atStartOfDay(ZoneOffset.UTC).toInstant();
LocalDate endDate = startDate.plusWeeks(1);
Instant endInstant = endDate.atStartOfDay(ZoneOffset.UTC).toInstant();
System.out.println("" + startInstant + " - " + endInstant);
My locale uses ISO week numbers. The output here was:
2019-12-29T00:00:00Z - 2020-01-05T00:00:00Z
If you want ISO weeks independently of the locale, set wf to WeekFields.ISO. If you want some other week numbering scheme, set wf accordingly.
In case any other readers were wondering, Kirill is defining the end of the week as the first moment of the following week. This is recommended. It’s known as using half-open intervals for time intervals.
I also agree with the question that one should clearly prefer using java.time for this task rather than Calendar. Calendar is poorly designed and long outdated, and I believe that the code using java.time is clearer to read.
Furthermore, the code in the question using Calendar doesn’t set the day to the first day of the week, so will not give you that day. And while I haven’t tested, I suspect that the code will sometimes produce unexpected results around New Year.
My code using WeekFields from java.time will stay within the current week-based year, which is not the same as the calendar year. For example, if I had run it on December 30, 2019, it would still have given med week 1 of 2020 because we were already in that week.
You could adjust the week using the following methods:
LocalDateTime localDateTime = LocalDateTime.of(2020, 1, 1, 0, 0);
System.out.println(localDateTime); //2020-01-01T00:00
localDateTime = localDateTime.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 2);
System.out.println(localDateTime); //2020-01-08T00:00
localDateTime = localDateTime.plusWeeks(10);
System.out.println(localDateTime); //2020-03-18T00:00
and to parse it to Instant depends on what class from the API you are using:
LocalDateTime.now().toInstant(ZoneOffset.of("+04:00"));
ZonedDateTime.now().toInstant();
The LocalDateTime doest not have a Zone, so you must a provide a ZoneOffset to parse it to a Instant.
In order to set the month you can use this lambda expression:
LocalDate.now().with(temporal
-> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
);
Now get instant is easy:
LocalDate localDate = LocalDate.now().with(temporal
-> temporal.with(ChronoField.ALIGNED_WEEK_OF_YEAR, 1l)
);
Instant instant = localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant();
If you don't want cto change time, then you can use this instead of last line:
Instant instant = localDate.atTime(LocalTime.now()).atZone(ZoneId.systemDefault()).toInstant();
Related
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar calender = Calendar.getInstance();
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMaximum(Calendar.DATE));
int months = 1;
calender.add(Calendar.MONTH, months );
String time = sdf .format(calender .getTime());
System.out.println(time);
Since current month is April and last date is 2020-04-30
Next month last date I should get 2020-05-31
but I am getting last date as 2020-05-30
Any thing am i doing wrong ?
java.time
I recommend that you use java.time, the modern Java date and time API, for your date work. It’s much nicer to work with than the old classes Calendar and SimpleDateFormat.
LocalDate endOfNextMonth =
YearMonth // Represent an entire month in a particular year.
.now(ZoneId.of("Europe/Volgograd")) // Capture the current year-month as seen in a particular time zone. Returns a `YearMonth` object.
.plusMonths(1) // Move to the next month. Returns another `YearMonth` object.
.atEndOfMonth(); // Determine the last day of that year-month. Returns a `LocalDate` object.
String time = endOfNextMonth.toString(); // Represent the content of the `LocalDate` object by generating text in standard ISO 8601 format.
System.out.println("Last day of next month: " + time);
Output when running today:
Last day of next month: 2020-05-31
A YearMonth, as the name maybe says, is a year and month without day of month. It has an atEndOfMonth method that conveniently gives us the last day of the month as a LocalDate. A LocalDate is a date without time of day, so what we need here. And its toString method conveniently gives the format that you wanted (it’s ISO 8601).
Depending on the reason why you want the last day of another month there are a couple of other approaches you may consider. If you need to handle date ranges that always start and end on month boundaries, you may either:
Represent your range as a range of YearMonth objects. Would this free you from knowing the last day of the month altogether?
Represent the end of your range as the first of the following month exclusive. Doing math on the 1st of each month is simpler since it is always day 1 regardless of the length of the month.
What went wrong in your code?
No matter if using Calendar, LocalDate or some other class you need to do things in the opposite order: first add one month, then find the end of the month. As you know, months have different lengths, so the important part is getting the end of that month where you want to get the last day. Putting it the other way: setting either a LocalDate or a Calendar to the last day of the month correctly sets it to the last day of the month in qustion but does not instruct it to stay at the last day of the month after subsequent changes to its value, such as adding a month. If you add a month to April 29, you get May 29. If you add a month to April 30, you get May 30. Here it doesn’t matter that 30 is the last day of April while 30 is not the last day of May.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Wikipedia article: ISO 8601
You'd better use LocalDate like this:
LocalDate now = LocalDate.now();
LocalDate lastDay = now.withDayOfMonth(now.lengthOfMonth());
LocalDate nextMonth = lastDay.plusMonths(1);
Don't use deprecated classes from java.util.*.
Use classes from java.time.*.
Example with LocalDate :
public class Testing {
public static void main(String args[]) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.now();
int months = 1;
date = date.plusMonths(months);
date = date.withDayOfMonth(date.lengthOfMonth());
System.out.println(date.format(dateTimeFormatter));
}
}
Output :
2020-05-31
Example with Calendar :
public class Testing {
public static void main(String args[]) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar calender = Calendar.getInstance();
int months = 1;
calender.add(Calendar.MONTH, months);
calender.set(Calendar.DAY_OF_MONTH, calender.getActualMaximum(Calendar.DAY_OF_MONTH));
String time = sdf.format(calender.getTime());
System.out.println(time);
}
}
Output :
2020-05-31
Initialize java.util.Calendar with May, 31 1900. Then add one year to it twenty times.
Here's code:
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
fun main(args : Array<String>) {
val f = SimpleDateFormat("yyyy.dd.MM")
val cal = Calendar.getInstance()
cal.set(1900, Calendar.MAY, 31)
for(i in 1..20) {
println(f.format(cal.time))
cal.add(Calendar.YEAR, 1)
}
}
The output is following:
1900.31.05
1901.31.05
1902.31.05
1903.31.05
1904.31.05
1905.31.05
1906.31.05
1907.31.05
1908.31.05
1909.31.05
1910.31.05
1911.31.05
1912.31.05
1913.31.05
1914.31.05
1915.31.05
1916.31.05
1917.31.05
1918.01.06
1919.01.06
Why I get June, 1 instead of May, 31 since 1918?
UPD: with time information
1917.31.05 23:38:50.611
1918.01.06 01:38:50.611
If this is DST invention, how do I prevent that?
You seem to be running your code in a timezone that changed its offset by two hours in 1917 or 1918. That is, the number of hours ahead or behind UTC changed. I've no idea why your timezone would have done that, but I'm sure there's a good historical reason for it.
If you're only interested in dates, without the Time component, use the java.time.LocalDate class, which effectively represents a day, month and year only. It's not subject to any daylight savings anomalies.
LocalDate today = LocalDate.now();
or
LocalDate moonLanding = LocalDate.of(1969, 7, 20);
I am assuming that you are in Europe/Moscow time zone. Turing85 in a comment correctly spotted the cause of the behaviour you observed: In 1918 summer time (DST) in your time zone began on May 31. The clock was moved forward from 22:00 to 24:00, that is, by two hours. Your Calendar object is aware of this and therefore refuses to give 23:38:50.611 on this date. Instead it picks the time 2 hours later, 1918.01.06 01:38:50.611. Now the month and day-of-month have changed to 1st of June.
Unfortunately this change is kept in the Calendar and carried on to the following year.
If this is DST invention, how do I prevent that?
Thomas Kläger in a comment gave the right solution: If you only need the dates, use LocalDate from java.time:
DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("uuuu.dd.MM");
LocalDate date = LocalDate.of(1900, Month.MAY, 31);
for (int i = 1; i <= 20; i++) {
System.out.println(date.format(dateFormatter));
date = date.plusYears(1);
}
Output (abbreviated):
1900.31.05
1901.31.05
…
1917.31.05
1918.31.05
1919.31.05
The “local” in LocalDate means “without timezone” in java.time jargon, so this is guaranteed to keep you free of surprises from time zone anomalies.
If you need a time, you may consider LocalDateTime, but since this is without time zone too, it will give you the non-existing time of 1918.31.05 23:38:50.611, so maybe not.
An alternative thing you may consider is adding the right number of years to your origin of 1900.31.05 23:38:50.611. Then at least you will only have surprises in years where you hit a non-existing time. I am using ZonedDateTime for this demonstration:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu.dd.MM HH:mm:ss.SSS");
ZonedDateTime originalDateTime = ZonedDateTime.of(1900, Month.MAY.getValue(), 31,
23, 30, 50, 611000000, ZoneId.of("Europe/Moscow"));
for (int i = 0; i < 25; i++) {
System.out.println(originalDateTime.plusYears(i).format(formatter));
}
Output:
1900.31.05 23:30:50.611
1901.31.05 23:30:50.611
…
1917.31.05 23:30:50.611
1918.01.06 01:30:50.611
1919.01.06 00:30:50.611
1920.31.05 23:30:50.611
…
1924.31.05 23:30:50.611
Again in 1919 summer time began on May 31. This time the clock was only advanced by 1 hour, from 23 to 24, so you get only 1 hour later than the imaginary time of 23:30:50.611.
I am recommending java.time for date and time work, not least when doing math on dates like you do. The Calendar class is considered long outmoded. java.time was designed acknowledging that Calendar and the other old classes were poorly designed. The modern ones are so much nicer to work with.
How could I be sure it was Moscow?
In no other time zone than Europe/Moscow is the time of 1918.31.05 23:38:50.611 nonexistent. I checked:
LocalDateTime dateTime = LocalDateTime.of(1918, Month.MAY, 31, 23, 38, 50, 611000000);
for (String zid : ZoneId.getAvailableZoneIds()) {
ZonedDateTime zdt = dateTime.atZone(ZoneId.of(zid));
LocalDateTime newDateTime = zdt.toLocalDateTime();
if (! newDateTime.equals(dateTime)) {
System.out.println(zid + ": -> " + zdt + " -> " + newDateTime);
}
}
Output:
Europe/Moscow: -> 1918-06-01T01:38:50.611+04:31:19[Europe/Moscow] -> 1918-06-01T01:38:50.611
W-SU: -> 1918-06-01T01:38:50.611+04:31:19[W-SU] -> 1918-06-01T01:38:50.611
“W-SU” is a deprecated name for the same time zone, it stands for Western Soviet Union.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Time Changes in Moscow Over the Years
List of tz database time zones showing W-SU as deprecated.
An old message on an IANA mailing list stating “But long ago … we based the name on some more-political entity than a city name. For example, we used "W-SU" for the western Soviet Union…”
I have a date in dd/mm (15/07) format, I need to add a single day to this date, so it becomes 16/07.
How can I do this in the easiest way in java?
You can use Calendar.
String dt = "15-07-2016";
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");
Calendar c = Calendar.getInstance();
c.setTime(sdf.parse(dt));
c.add(Calendar.DATE, 1); // number of days to add
dt = sdf.format(c.getTime());
You can do this:
public String addDay(String date) {
String[] dateSplit = date.split("/");
String day = "" + (Integer.parseInt(dateSplit[0]) + 1);
return day + "/" + dateSplit[1];
}
But this isn't really a nice solution, because this doesn't handle month or year swaps (This you can add by yourself using the % operator)
Or you use the SimpleDateFormat like here: How can I increment a date by one day in Java?
java.time
The Answer by Goel is correct but outmoded.
The java.time framework is built into Java 8 and later. These classes supplant the old troublesome date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.
MonthDay
The java.time classes include the MonthDay class to represent a month+day without year and without time zone.
String input = "15/07";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern( "dd/MM" );
MonthDay monthDay = MonthDay.parse( input , formatter );
Cannot increment February 28
As commented by Tom, you cannot reliably increment February 28. In most years you would get March 1 but in leap years you get February 29. This is why the YearMonth class lacks any addDays method.
So you need to (a) assume/supply a year, (b) refuse to increment the one day of February 28, or (c) arbitrarily increment to March 1 from February 28 to ignore any possible 29th.
Let's look at the first option, supplying a year.
To get the current year we need the current date. To get the current date, specify a time zone. For any given moment, the date varies around the globe by zone.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
int year = today.getYear();
We can apply that year number to change our YearMonth into a LocalDate. From there the LocalDate::plusDays method increments to the next day. From the resulting instance of LocalDate we extract a YearMonth object.
LocalDate ld = monthYear.atYear( year );
LocalDate nextDay = ld.plusDays( 1 );
YearMonth ymNextDay = MonthDay.from( nextDay );
I have to calculate in Java what is the number of the current day in the year.
For example if today is the 1 of January the resut should be 1. If it is the 5 of February the result should be 36
How can I automatically do it in Java? Exist some class (such as Calendar) that natively supports this feature?
With Java 8:
LocalDate date = LocalDate.of(2015, 2, 5);
int dayNum = date.getDayOfYear();
You can use java.util.Calendar class. Be careful that month is zero based. So in your case for the first of January it should be:
Calendar calendar = new GregorianCalendar(2015, 0, 1);
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
Calendar#get(Calendar.DAY_OF_YEAR);
int dayOfYear = Calendar.getInstance().get(Calendar.DAY_OF_YEAR);
In Joda-Time 2.7:
int dayOYear = DateTime.now().getDayOfYear();
Time zone is crucial in determining a day. The code above uses the JVM's current default time zone. Usually better to specify a time zone.
DateTimeZone zone = DateTimeZone.forID( "America/Montreal" );
int dayOYear = DateTime.now( zone ).getDayOfYear();
My API allows library client to pass Date:
method(java.util.Date date)
Working with Joda-Time, from this date I would like to extract the month and iterate over all days this month contains.
Now, the passed date is usually new Date() - meaning current instant. My problem actually is setting the new DateMidnight(jdkDate) instance to be at the start of the month.
Could someone please demonstrates this use case with Joda-Time?
Midnight at the start of the first day of the current month is given by:
// first midnight in this month
DateMidnight first = new DateMidnight().withDayOfMonth(1);
// last midnight in this month
DateMidnight last = first.plusMonths(1).minusDays(1);
If starting from a java.util.Date, a different DateMidnight constructor is used:
// first midnight in java.util.Date's month
DateMidnight first = new DateMidnight( date ).withDayOfMonth(1);
Joda Time java doc - https://www.joda.org/joda-time/apidocs/overview-summary.html
An alternative way (without taking DateMidnight into account) to get the first day of the month would be to use:
DateTime firstDayOfMonth = new DateTime().dayOfMonth().withMinimumValue();
First Moment Of The Day
The answer by ngeek is correct, but fails to put the time to the first moment of the day. To adjust the time, append a call to withTimeAtStartOfDay.
// © 2013 Basil Bourque. This source code may be used freely forever by anyone taking full responsibility for doing so.
org.joda.time.DateTime startOfThisMonth = new org.joda.time.DateTime().dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
org.joda.time.DateTime startofNextMonth = startOfThisMonth.plusMonths( 1 ).dayOfMonth().withMinimumValue().withTimeAtStartOfDay();
System.out.println( "startOfThisMonth: " + startOfThisMonth );
System.out.println( "startofNextMonth: " + startofNextMonth );
When run in Seattle US…
startOfThisMonth: 2013-11-01T00:00:00.000-07:00
startofNextMonth: 2013-12-01T00:00:00.000-08:00
Note the difference in those two lines of console output: -7 vs -8 because of Daylight Saving Time.
Generally one should always specify the time zone rather than rely on default. Omitted here for simplicity. One should add a line like this, and pass the time zone object to the constructors used in example above.
// Time Zone list: http://joda-time.sourceforge.net/timezones.html (Possibly out-dated, read note on that page)
// UTC time zone (no offset) has a constant, so no need to construct: org.joda.time.DateTimeZone.UTC
org.joda.time.DateTimeZone kolkataTimeZone = org.joda.time.DateTimeZone.forID( "Asia/Kolkata" );
java.time
The above is correct but outdated. The Joda-Time library is now supplanted by the java.time framework built into Java 8 and later.
The LocalDate represents a date-only value without time-of-day and without time zone. A time zone is crucial in determine a date. For any given moment the date varies by zone around the globe.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
LocalDate today = LocalDate.now( zoneId );
Use one of the TemporalAdjusters to get first of month.
LocalDate firstOfMonth = today.with( TemporalAdjusters.firstDayOfMonth() );
The LocalDate can generate a ZonedDateTime that represents the first moment of the day.
ZonedDateTime firstMomentOfCurrentMonth = firstOfMonth.atStartOfDay( zoneId );
Oh, I did not see that this was about jodatime. Anyway:
Calendar c = Calendar.getInstance();
c.setTime(date);
c.set(Calendar.HOUR_OF_DAY, 0);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
int min = c.getActualMinimum(Calendar.DAY_OF_MONTH);
int max = c.getActualMaximum(Calendar.DAY_OF_MONTH);
for (int i = min; i <= max; i++) {
c.set(Calendar.DAY_OF_MONTH, i);
System.out.println(c.getTime());
}
Or using commons-lang:
Date min = DateUtils.truncate(date, Calendar.MONTH);
Date max = DateUtils.addMonths(min, 1);
for (Date cur = min; cur.before(max); cur = DateUtils.addDays(cur, 1)) {
System.out.println(cur);
}
DateMidnight is now deprecated. Instead you can do:
LocalDate firstOfMonth = new LocalDate(date).withDayOfMonth(1);
LocalDate lastOfMonth = firstOfMonth.plusMonths(1).minusDays(1);
If you know the time zone use new LocalDate(date, timeZone) instead for greater accuracy.
You can also do .dayOfMonth().withMinimumValue() instead of .withDayOfMonth(1)
EDIT:
This will give you 12/1/YYYY 00:00 and 12/31/YYYY 00:00. If you rather the last of the month be actually the first of the next month (because you are doing a between clause), then remove the minusDays(1) from the lastOfMonth calculation
You can get Start date and end date of month using this:
DateTime monthStartDate = new DateTime().dayOfMonth().withMinimumValue();
DateTime monthEndDate = new DateTime().dayOfMonth().withMaximumValue();