Convert GMT Timestamp to local Calendar to particular timezone [duplicate] - java

I have to print the EST time in my Java application. I had set the time zone to EST using:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
But when the daylight savings is being followed in this timezone, my code does not print the correct time (it prints 1 hour less).
How to make the code work to read the correct time always, irrespective of whether the daylight savings are being observed or not?
PS: I tried setting the timezone to EDT, but it doesn't solve the problem.

This is the problem to start with:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST"));
The 3-letter abbreviations should be wholeheartedly avoided in favour of TZDB zone IDs. EST is Eastern Standard Time - and Standard time never observes DST; it's not really a full time zone name. It's the name used for part of a time zone. (Unfortunately I haven't come across a good term for this "half time zone" concept.)
You want a full time zone name. For example, America/New_York is in the Eastern time zone:
TimeZone zone = TimeZone.getTimeZone("America/New_York");
DateFormat format = DateFormat.getDateTimeInstance();
format.setTimeZone(zone);
System.out.println(format.format(new Date()));

Other answers are correct, especially the one by Jon Skeet, but outdated.
java.time
These old date-time classes have been supplanted by the java.time framework built into Java 8 and later.
If you simply want the current time in UTC, use the Instant class.
Instant now = Instant.now();
EST is not a time zone, as explained in the correct Answer by Jon Skeet. Such 3-4 letter codes are neither standardized nor unique, and further the confusion over Daylight Saving Time (DST). Use a proper time zone name in the "continent/region" format.
Perhaps you meant Eastern Standard Time in east coast of north America? Or Egypt Standard Time? Or European Standard Time?
ZoneId zoneId = ZoneId.of( "America/New_York" );
ZoneId zoneId = ZoneId.of( "Africa/Cairo" );
ZoneId zoneId = ZoneId.of( "Europe/Lisbon" );
Use any such ZoneId object to get the current moment adjusted to a particular time zone to produce a ZonedDateTime object.
ZonedDateTime zdt = ZonedDateTime.now( zoneId ) ;
Adjust that ZonedDateTime into a different time zone by producing another ZonedDateTime object from the first. The java.time framework uses immutable objects rather than changing (mutating) existing objects.
ZonedDateTime zdtGuam = zdt.withZoneSameInstant( ZoneId.of( "Pacific/Guam" ) ) ;

Instead of entering "EST" for the timezone you can enter "EST5EDT" as such. As you noted, just "EDT" does not work. This will account for the daylight savings time issue. The code line looks like this:
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("EST5EDT"));

As per this answer:
TimeZone tz = TimeZone.getTimeZone("EST");
boolean inDs = tz.inDaylightTime(new Date());

private static Long DateTimeNowTicks(){
long TICKS_AT_EPOCH = 621355968000000000L;
TimeZone timeZone = Calendar.getInstance().getTimeZone();
int offs = timeZone.getRawOffset();
if (timeZone.inDaylightTime(new Date()))
offs += 60 * 60 * 1000;
return (System.currentTimeMillis() + offs) * 10000 + TICKS_AT_EPOCH;
}

public static float calculateTimeZone(String deviceTimeZone) {
float ONE_HOUR_MILLIS = 60 * 60 * 1000;
// Current timezone and date
TimeZone timeZone = TimeZone.getTimeZone(deviceTimeZone);
Date nowDate = new Date();
float offsetFromUtc = timeZone.getOffset(nowDate.getTime()) / ONE_HOUR_MILLIS;
// Daylight Saving time
if (timeZone.useDaylightTime()) {
// DST is used
// I'm saving this is preferences for later use
// save the offset value to use it later
float dstOffset = timeZone.getDSTSavings() / ONE_HOUR_MILLIS;
// DstOffsetValue = dstOffset
// I'm saving this is preferences for later use
// save that now we are in DST mode
if (timeZone.inDaylightTime(nowDate)) {
Log.e(Utility.class.getName(), "in Daylight Time");
return -(ONE_HOUR_MILLIS * dstOffset);
} else {
Log.e(Utility.class.getName(), "not in Daylight Time");
return 0;
}
} else
return 0;
}

In java, DateFormatter by default uses DST,To avoid day Light saving (DST) you need to manually do a trick,
first you have to get the DST offset i.e. for how many millisecond DST applied, for ex somewhere DST is also for 45 minutes and for some places it is for 30 min
but in most cases DST is of 1 hour
you have to use Timezone object and check with the date whether it is falling under DST or not and then you have to manually add offset of DST into it. for eg:
TimeZone tz = TimeZone.getTimeZone("EST");
boolean isDST = tz.inDaylightTime(yourDateObj);
if(isDST){
int sec= tz.getDSTSavings()/1000;// for no. of seconds
Calendar cal= Calendar.getInstance();
cal.setTime(yourDateObj);
cal.add(Calendar.Seconds,sec);
System.out.println(cal.getTime());// your Date with DST neglected
}

Implementing the TimeZone class to set the timezone to the Calendar takes care of the daylight savings.
java.util.TimeZone represents a time zone offset, and also figures out daylight savings.
sample code:
TimeZone est_timeZone = TimeZoneIDProvider.getTimeZoneID(TimeZoneID.US_EASTERN).getTimeZone();
Calendar enteredCalendar = Calendar.getInstance();
enteredCalendar.setTimeZone(est_timeZone);

Related

Convert LocalDateTime to LocalDateTime in UTC

Convert LocalDateTime to LocalDateTime in UTC.
LocalDateTime convertToUtc(LocalDateTime date) {
//do conversion
}
I searched over net. But did not get a solution
I personally prefer
LocalDateTime.now(ZoneOffset.UTC);
as it is the most readable option.
LocalDateTime does not contain Zone information. ZonedDatetime does.
If you want to convert LocalDateTime to UTC, you need to wrap by ZonedDateTime fist.
You can convert like the below.
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt.toLocalTime());
ZonedDateTime ldtZoned = ldt.atZone(ZoneId.systemDefault());
ZonedDateTime utcZoned = ldtZoned.withZoneSameInstant(ZoneId.of("UTC"));
System.out.println(utcZoned.toLocalTime());
There is an even simpler way
LocalDateTime.now(Clock.systemUTC())
Question?
Looking at the answers and the question, it seems the question has been modified significantly. So to answer the current question:
Convert LocalDateTime to LocalDateTime in UTC.
Timezone?
LocalDateTime does not store any information about the time-zone, it just basically holds the values of year, month, day, hour, minute, second, and smaller units. So an important question is: What is the timezone of the original LocalDateTime? It might as well be UTC already, therefore no conversion has to be made.
System Default Timezone
Considering that you asked the question anyway, you probably meant that the original time is in your system-default timezone and you want to convert it to UTC. Because usually a LocalDateTime object is created by using LocalDateTime.now() which returns the current time in the system-default timezone. In this case, the conversion would be the following:
LocalDateTime convertToUtc(LocalDateTime time) {
return time.atZone(ZoneId.systemDefault()).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}
An example of the conversion process:
2019-02-25 11:39 // [time] original LocalDateTime without a timezone
2019-02-25 11:39 GMT+1 // [atZone] converted to ZonedDateTime (system timezone is Madrid)
2019-02-25 10:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2019-02-25 10:39 // [toLocalDateTime] losing the timezone information
Explicit Timezone
In any other case, when you explicitly specify the timezone of the time to convert, the conversion would be the following:
LocalDateTime convertToUtc(LocalDateTime time, ZoneId zone) {
return time.atZone(zone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
}
An example of the conversion process:
2019-02-25 11:39 // [time] original LocalDateTime without a timezone
2019-02-25 11:39 GMT+2 // [atZone] converted to ZonedDateTime (zone is Europe/Tallinn)
2019-02-25 09:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2019-02-25 09:39 // [toLocalDateTime] losing the timezone information
The atZone() Method
The result of the atZone() method depends on the time passed as its argument, because it considers all the rules of the timezone, including Daylight Saving Time (DST). In the examples, the time was 25th February, in Europe this means winter time (no DST).
If we were to use a different date, let's say 25th August from last year, the result would be different, considering DST:
2018-08-25 11:39 // [time] original LocalDateTime without a timezone
2018-08-25 11:39 GMT+3 // [atZone] converted to ZonedDateTime (zone is Europe/Tallinn)
2018-08-25 08:39 GMT // [withZoneSameInstant] converted to UTC, still as ZonedDateTime
2018-08-25 08:39 // [toLocalDateTime] losing the timezone information
The GMT time does not change. Therefore the offsets in the other timezones are adjusted. In this example, the summer time of Estonia is GMT+3, and winter time GMT+2.
Also, if you specify a time within the transition of changing clocks back one hour. E.g. October 28th, 2018 03:30 for Estonia, this can mean two different times:
2018-10-28 03:30 GMT+3 // summer time [UTC 2018-10-28 00:30]
2018-10-28 04:00 GMT+3 // clocks are turned back 1 hour [UTC 2018-10-28 01:00]
2018-10-28 03:00 GMT+2 // same as above [UTC 2018-10-28 01:00]
2018-10-28 03:30 GMT+2 // winter time [UTC 2018-10-28 01:30]
Without specifying the offset manually (GMT+2 or GMT+3), the time 03:30 for the timezone Europe/Tallinn can mean two different UTC times, and two different offsets.
Summary
As you can see, the end result depends on the timezone of the time passed as an argument. Because the timezone cannot be extracted from the LocalDateTime object, you have to know yourself which timezone it is coming from in order to convert it to UTC.
Use the below. It takes the local datetime and converts it to UTC using the timezone. You do not need to create it function.
ZonedDateTime nowUTC = ZonedDateTime.now(ZoneOffset.UTC);
System.out.println(nowUTC.toString());
If you need to obtain the LocalDateTime part of the ZonedDateTime then you can use the following.
nowUTC.toLocalDateTime();
Here is a static method i use in my application to insert UTC time in mysql since i cannot add a default value UTC_TIMESTAMP to a datetime column.
public static LocalDateTime getLocalDateTimeInUTC(){
ZonedDateTime nowUTC = ZonedDateTime.now(ZoneOffset.UTC);
return nowUTC.toLocalDateTime();
}
Here's a simple little utility class that you can use to convert local date times from zone to zone, including a utility method directly to convert a local date time from the current zone to UTC (with main method so you can run it and see the results of a simple test):
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public final class DateTimeUtil {
private DateTimeUtil() {
super();
}
public static void main(final String... args) {
final LocalDateTime now = LocalDateTime.now();
final LocalDateTime utc = DateTimeUtil.toUtc(now);
System.out.println("Now: " + now);
System.out.println("UTC: " + utc);
}
public static LocalDateTime toZone(final LocalDateTime time, final ZoneId fromZone, final ZoneId toZone) {
final ZonedDateTime zonedtime = time.atZone(fromZone);
final ZonedDateTime converted = zonedtime.withZoneSameInstant(toZone);
return converted.toLocalDateTime();
}
public static LocalDateTime toZone(final LocalDateTime time, final ZoneId toZone) {
return DateTimeUtil.toZone(time, ZoneId.systemDefault(), toZone);
}
public static LocalDateTime toUtc(final LocalDateTime time, final ZoneId fromZone) {
return DateTimeUtil.toZone(time, fromZone, ZoneOffset.UTC);
}
public static LocalDateTime toUtc(final LocalDateTime time) {
return DateTimeUtil.toUtc(time, ZoneId.systemDefault());
}
}
Try this using this method.
convert your LocalDateTime to ZonedDateTime by using the of method and pass system default time zone or you can use ZoneId of your zone like ZoneId.of("Australia/Sydney");
LocalDateTime convertToUtc(LocalDateTime dateTime) {
ZonedDateTime dateTimeInMyZone = ZonedDateTime.
of(dateTime, ZoneId.systemDefault());
return dateTimeInMyZone
.withZoneSameInstant(ZoneOffset.UTC)
.toLocalDateTime();
}
To convert back to your zone local date time use:
LocalDateTime convertFromUtc(LocalDateTime utcDateTime){
return ZonedDateTime.
of(utcDateTime, ZoneId.of("UTC"))
.toOffsetDateTime()
.atZoneSameInstant(ZoneId.systemDefault())
.toLocalDateTime();
}
tldr: there is simply no way to do that; if you are trying to do that, you get LocalDateTime wrong.
The reason is that LocalDateTime does not record Time Zone after instances are created. You cannot convert a date time without time zone to another date time based on a specific time zone.
As a matter of fact, LocalDateTime.now() should never be called in production code unless your purpose is getting random results. When you construct a LocalDateTime instance like that, this instance contains date time ONLY based on current server's time zone, which means this piece of code will generate different result if it is running a server with a different time zone config.
LocalDateTime can simplify date calculating. If you want a real universally usable data time, use ZonedDateTime or OffsetDateTime: https://docs.oracle.com/javase/8/docs/api/java/time/OffsetDateTime.html.
you can implement a helper doing something like that :
public static LocalDateTime convertUTCFRtoUTCZ(LocalDateTime dateTime) {
ZoneId fr = ZoneId.of("Europe/Paris");
ZoneId utcZ = ZoneId.of("Z");
ZonedDateTime frZonedTime = ZonedDateTime.of(dateTime, fr);
ZonedDateTime utcZonedTime = frZonedTime.withZoneSameInstant(utcZ);
return utcZonedTime.toLocalDateTime();
}
public static String convertFromGmtToLocal(String gmtDtStr, String dtFormat, TimeZone lclTimeZone) throws Exception{
if (gmtDtStr == null || gmtDtStr.trim().equals("")) return null;
SimpleDateFormat format = new SimpleDateFormat(dtFormat);
format.setTimeZone(getGMTTimeZone());
Date dt = format.parse(gmtDtStr);
format.setTimeZone(lclTimeZone);
return
format.format(dt);
}

How to get and set specified time in java.time.Instant?

I have two java.time.Instant objects
Instant dt1;
Instant dt2;
I want to get time (only hours and minutes without date) from dt2 and set it to dt1. What is the best way to to this? Using
dt2.get(ChronoField.HOUR_OF_DAY)
throws java.time.temporal.UnsupportedTemporalTypeException
You have to interpret the Instant at some time zone to get ZonedDateTime. As an Instant measures the ellapsed seconds and nano seconds from epoch 1970-01-01T00:00:00Z you should use UTC to get the same time as the Instant would print. (Z ≙ Zulu Time ≙ UTC)
Getting the time
Instant instant;
// get overall time
LocalTime time = instant.atZone(ZoneOffset.UTC).toLocalTime();
// get hour
int hour = instant.atZone(ZoneOffset.UTC).getHour();
// get minute
int minute = instant.atZone(ZoneOffset.UTC).getMinute();
// get second
int second = instant.atZone(ZoneOffset.UTC).getSecond();
// get nano
int nano = instant.atZone(ZoneOffset.UTC).getNano();
There are also methods to get days, month and year (getX).
Setting the time
Instants are immutable so you can only "set" the time by creating a copy of your instant with the given time change.
instant = instant.atZone(ZoneOffset.UTC)
.withHour(hour)
.withMinute(minute)
.withSecond(second)
.withNano(nano)
.toInstant();
There are also methods to alter days, month and year (withX) as well as methods to add (plusX) or subtract (minusX) time or date values.
To set the time to a value given as a string use: .with(LocalTime.parse("12:45:30"))
Instant does not have any hour / minute. Please read the documentation of Instant class : https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html
If you use System Timezone to convert the Instant , you can use something like this :
LocalDateTime ldt1 = LocalDateTime.ofInstant(dt1, ZoneId.systemDefault());
LocalDateTime ldt2 = LocalDateTime.ofInstant(dt2, ZoneId.systemDefault());
ldt1 = ldt1
.withHour(ldt2.getHour())
.withMinute(ldt2.getMinute())
.withSecond(ldt2.getSecond());
dt1 = ldt1.atZone(ZoneId.systemDefault()).toInstant();
Convert first the Instant to LocalDateTime, and use UTC as its timezone, then you can get its hours.
import java.time.*
LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).getHour()
While the upper answer is a good, I used it but in Kotlin. Thankyou #frido
while (startDate.isBefore(endDate)) {
val year: Int = startDate.atZone(ZoneOffset.UTC).year
val month: Int = startDate.atZone(ZoneOffset.UTC).monthValue
val day: Int = startDate.atZone(ZoneOffset.UTC).dayOfMonth
System.out.printf("%d.%d.%d\n", day, month, year)
startDate = startDate.atZone(ZoneOffset.UTC).withDayOfMonth(
day + 1
).toInstant()
}

How to get DST offset with Joda Time

In my java program I do something like this
1.)
LocalDateTime currentDateTime = new LocalDateTime();
LocalDateTime newDateTime = new LocalDateTime(currentDateTime);
newDateTime = newDateTime.plusDays(daysOffset);
newDateTime = newDateTime.plusHours(hoursOffset);
newDateTime = newDateTime.plusMinutes(minutesOffset);
Later in the code I do
2.)
boolean newDateTimeIsInWinter =
dateTimeZone.getOffset(newDateTime.toDateTime().getMillis()) == dateTimeZone.getStandardOffset(newDateTime.toDateTime().getMillis());
The of call newDateTime.toDateTime() may result java.lang.IllegalArgumentException: Illegal instant due to time zone offset transition.
So I'd like to put something like this between 1.) and 2.)
if (dateTimeZone.isLocalDateTimeGap(newDateTime))
{
int dstOffsetMinutes = ???;
newDateTime = newDateTime.plusMinutes(dstOffsetMinutes);
}
Can anyone tell me the right replacement for ??? It's not as easy as setting it to 60. For example the LHST timezone hast only 30 Minutes offset.
Ask DateTimeZome About DST
To determine if a particular moment is in Daylight Saving Time or not for a particular time zone, ask the [DateTimeZone][1] object.
boolean isStandardTime = DateTimeZone.forID( "America/Montreal" ).isStandardOffset( DateTime.now().getMillis() );
When To Use "Local" Classes
If you care about time zone, offsets, and Daylight Saving Time, do not use LocalDateTime, LocalDate, or LocalTime. That is what DateTime is for.
Use the "Local" classes when you mean a date and/or time in general not for a specific place or time zone. For example if you want to say “Christmas starts at 2014-12-25T00:00:00.000" that means at midnight on the morning of the 25th at any particular location. But that LocalDateTime could mean one DateTime for Paris but a different DateTime (different moment) in Montréal.
I solved my problem by using DateTime instead LocalDateTime
1.) now is
DateTime newDateTimeUTC = currentDateTime.toDateTime();
newDateTimeUTC = newDateTimeUTC.plusDays(daysOffset);
newDateTimeUTC = newDateTimeUTC.plusHours(hoursOffset);
newDateTimeUTC = newDateTimeUTC.plusMinutes(minutesOffset);
LocalDateTime newDateTime = newDateTimeUTC.toLocalDateTime();
2.) still is
boolean newDateTimeIsInWinter =
dateTimeZone.getOffset(newDateTime.toDateTime().getMillis()) == dateTimeZone.getStandardOffset(newDateTime.toDateTime().getMillis());
There is no need for isLocalDateTimeGap or anything else.
But this still does not anwser the original question How to get DST offset with Joda Time?

How to convert a UTC timestamp to local day, hour, minute in Java?

Given then timestamp 1245613885 that is a timestamp in GMT
How do I turn that into Year, Day, Hour, Minute values in Java using the server's local timezone info?
You can use java.util.Calendar for this. It offers a setTimeZone() method (which is by the way superfluous since it by default already picks the system default timezone).
long timestamp = 1245613885;
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getDefault());
calendar.setTimeInMillis(timestamp * 1000);
int year = calendar.get(Calendar.YEAR);
int day = calendar.get(Calendar.DATE);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
If you'd like to present it in a human readable date string, then I'd suggest SimpleDateFormat for this.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = sdf.format(calendar.getTime());
System.out.println(dateString); // 2009-06-21 15:51:25
(the output is correct as per my timezone GMT-4)
import java.util.Calendar;
import java.util.TimeZone;
public class Example{
public static void main(String[] args){
long utcTimestamp = 1285578547L;
Calendar cal = Calendar.getInstance(TimeZone.getDefault());
cal.setTimeInMillis(utcTimestamp * 1000);
System.out.println(cal.get(Calendar.YEAR));
System.out.println(cal.get(Calendar.MONTH));
System.out.println(cal.get(Calendar.DAY_OF_MONTH));
System.out.println(cal.get(Calendar.DAY_OF_YEAR));
System.out.println(cal.get(Calendar.HOUR));
System.out.println(cal.get(Calendar.MINUTE));
}
}
I would use something like Joda Time which is much faster than the JDK Date/Calendar classes and also doesn't have thread-safety issues with date parsing (not that your question relates to date parsing)
Basically you just need a formatter to do this
Date date = new Date(1245613885L*1000);
SimpleDateFormat formatter = new SimpleDateFormat('MM/dd/yyyy');
System.out.println(formatter.format(date));
tl;dr
Instant // Represent a moment in UTC.
.ofEpochMilli( 1_245_613_885L ) // Parse a count of milliseconds since the epoch reference of first moment of 1970 in UTC, 1970-01-01T00:00:00Z.
.atZone( // Adjust from UTC to the wall-clock time used by the people of a particular region (a time zone).
ZoneId.of( "Asia/Tokyo" ) // Or "America/Chicago" etc.
) // Returns a `ZonedDateTime` object.
.format( // Generate text representing the value of our `ZonedDateTime` object.
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL ) // Automatically localize the format and content of the string being generated.
.withLocale( Locale.CANADA_FRENCH ) // Or Locale.US etc.
) // Returns a `String` object.
jeudi 15 janvier 1970 à 19 h 00 min 13 s heure normale du Japon
java.time
The modern approach uses the java.time classes that supplanted the terrible date-time classes as of the adoption of JSR 310.
If your input 1245613885 is count of milliseconds since the first moment of 1970 in UTC, then parse as an Instant (a moment in UTC).
Instant instant = Instant.ofEpochMilli( 1_245_613_885L ) ;
Generate a string representing the value of that Instant object using standard ISO 8601 format.
String output = instant.toString() ;
Adjust from UTC to the wall-clock time used by the people of a particular region( a time zone).
Specify a proper time zone name in the format of Continent/Region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 2-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" ) ;
If you want to use the JVM’s current default time zone, ask for it and pass as an argument. If omitted, the code becomes ambiguous to read in that we do not know for certain if you intended to use the default or if you, like so many programmers, were unaware of the issue.
ZoneId z = ZoneId.systemDefault() ; // Get JVM’s current default time zone.
Apply a ZoneId to the Instant to get a ZonedDateTime.
ZonedDateTime zdt = instant.atZone( z ) ; // Same moment as the `instant`, but different wall-clock time.
Generate a string representing the value of that ZonedDateTime object using standard ISO 8601 format extended to append the name of the zone in square brackets.
String output = zdt.toString() ;
For other formats, either specify your own custom formatting pattern or let java.time automatically localize. For either route, use DateTimeFormatter. Search Stack Overflow as this has been handled many times already.
Calendar calendar = new GregorianCalendar(TimeZone.getTimeZone("America/Los_Angeles"), Locale.US);
calendar.setTimeInMillis(1245613885 * 1000);
int year = calendar.get(Calendar.YEAR);
int day = calendar.get(Calendar.DAY_OF_YEAR);
int hour = calendar.get(Calendar.HOUR_OF_DAY);
int minute = calendar.get(Calendar.MINUTE);
Change the TimeZone value you're passing into the Calendar object's constructor if you need a different time zone.

In Joda-Time, set DateTime to start of month

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();

Categories