In Joda Time, one can easily use the DateTimeZone.isLocalDateTimeGap method to tell if a local date and time is invalid because it falls into the gap created by a spring-forward daylight saving time transition.
DateTimeZone zone = DateTimeZone.forID("America/New_York");
LocalDateTime ldt = new LocalDateTime(2013, 3, 10, 2, 0);
boolean inGap = zone.isLocalDateTimeGap(ldt); // true
But how do you detect the fall-back transition? In other words, if a local date and time could be ambiguous because there is an overlap, how do you detect that? I would expect something like zone.isLocalDateTimeOverlap, but it doesn't exist. If it did, I would use it like so:
DateTimeZone zone = DateTimeZone.forID("America/New_York");
LocalDateTime ldt = new LocalDateTime(2013, 11, 3, 1, 0);
boolean overlaps = zone.isLocalDateTimeOverlap(ldt); // true
The Joda-Time documentation is clear that if there is an overlap during conversions, it will take the earlier possibility unless told otherwise. But it doesn't say how to detect that behavior.
Take advantage of withEarlierOffsetAtOverlap()
public static boolean isInOverlap(LocalDateTime ldt, DateTimeZone dtz) {
DateTime dt1 = ldt.toDateTime(dtz).withEarlierOffsetAtOverlap();
DateTime dt2 = dt1.withLaterOffsetAtOverlap();
return dt1.getMillis() != dt2.getMillis();
}
public static void test() {
// CET DST rolls back at 2011-10-30 2:59:59 (+02) to 2011-10-30 2:00:00 (+01)
final DateTimeZone dtz = DateTimeZone.forID("CET");
LocalDateTime ldt1 = new LocalDateTime(2011,10,30,1,50,0,0); // not in overlap
LocalDateTime ldt2 = new LocalDateTime(2011,10,30,2,50,0,0); // in overlap
System.out.println(ldt1 + " is in overlap? " + isInOverlap(ldt1, dtz));
System.out.println(ldt2 + " is in overlap? " + isInOverlap(ldt2, dtz));
}
Related
Using the following code:
class Test {
public static void main(String [] args) {
LocalDate date = LocalDate.of(2018, 11, 4);
LocalTime time = LocalTime.of(1, 59);
ZonedDateTime dt = ZonedDateTime.of(date, time, ZoneId.of("America/New_York"));
System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
dt = dt.plusMinutes(1);
System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
dt = dt.plusMinutes(59);
System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
dt = dt.plusMinutes(1);
System.out.println(dt.getHour() + ":" + dt.getMinute() + ":" + dt.getSecond());
}
}
I get
1:59:0
1:0:0
1:59:0
2:0:0
Is there a way to get to the 1:00:00 from after daylight saving time without going through the 1:00:00 from before daylight saving time?
Use ofStrict to specify which offset you want the resulting zoned date time to be on. America/New_York changes from -04:00 to -05:00 at around the time in question, so you want ZoneOffset.ofHours(-5).
ZonedDateTime dt = ZonedDateTime.ofStrict(
LocalDateTime.of(date, time),
ZoneOffset.ofHours(-5),
ZoneId.of("America/New_York")
);
In case you cannot hardcode the offset in, you can get the offset after using:
var dateTime = LocalDateTime.of(date, time)
var zone = ZoneId.of("America/New_York");
var offsetAfter = zone.getRules()
.getTransition(dateTime)
.getOffsetAfter();
ZonedDateTime dt = ZonedDateTime.ofStrict(
dateTime,
offsetAfter,
zone
);
Or, as Ole V.V. pointed out, you can also use the much shorter:
ZonedDateTime dt = ZonedDateTime.of(
date, time, ZoneId.of("America/New_York")
).withLaterOffsetAtOverlap();
The problem with time zones that honor Daylight Saving Time is that such times are ambiguous. The "America/New_York" zone has two times that are both labeled 2008-11-04T01:00:00. Technically, one of them is 01:00 EDT and the other is 01:00 EST, but not a lot of software will let you make the distinction that way, not least since such three-letter time zone designations are not necessarily globally unique.
The solution is to specify the time either in or relative to Universal time, which doesn't have daylight saving: the first 01:00 Eastern time is 05:00Z, and the second is 06:00Z. So you can either give the time as one of those and the zone as "UTC" (and then convert the result to "America/New_York"), or specify the offset from UTC using ofStrict.
I have some time Strings such as "09:00" and "17:30" and I need to check if the current time is between that range.
I thought I could make this comparison:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date now = new Date();
Date begin;
Date end;
begin = format.parse(begin_string);
end = format.parse(end_string);
if (now.compareTo(begin) > 0 && end.compareTo(now) > 0)
return true;
else
return false;
Turns out that when I parse the strings, the times are parsed correctly, but the date is set to Jan 1st 1970. This way, the code will always return false.
I'd like to know how can I set begin and end to the current date, but with the times from their strings.
You could also just reuse your format object for current time like this way:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date now = new Date();
String time = format.format(now); // format to wall time loosing current date
System.out.println(time);
now = format.parse(time); // reparse wall time
System.out.println(now);
So you transform now to 1970 using implicitly the standard time zone of your system and can then use it for direct comparisons with begin and end.
Date begin = format.parse("09:00");
Date end = format.parse("21:30");
return (begin.before(now) && end.after(now)); // open-bounded interval
Get current time, Calendar.getInstance();
Get another 2 instance of current time, and set time fields based on your input
For example:
Calendar.set(Calendar.HOUR_OF_DAY, 1);
and invoke compare() on the boundry of time
You should really use a Calendar. Then you can individually set the hours and minutes from values parsed from the string. Then get the time in milliseconds and compare those.
Date now = new Date();
Calendar cal = Calendar.getInstance();
cal.setTime(now);
cal.set(Calendar.HOUR_OF_DAY, hours);
cal.set(Calendar.MINUTE, minutes);
long time = cal.getTimeInMillis();
You could also use the wonderful Joda library. In my opinion Joda is a much better way to work with Dates and Times.
The bundled java.util.Date & .Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time library or the new java.time package found in Java 8 (inspired by Joda-Time, defined by JSR 310).
If you truly do not care about time zone or date, use either the Joda-Time LocalTime class or the java.time LocalTime class.
Caution: Naïve programmers often think they need only local time and can therefore ignore time zones, but then live to regret that position.
Joda-Time
If your times are in proper ISO 8601 format (24-hours, correct number of digits), then you can directly pass the string inputs to the constructor of LocalTime without bothering to parse. That class has a built-in ISO 8601 style parser.
String inputStart = "09:00";
String inputStop = "17:30";
LocalTime start = new LocalTime( inputStart );
LocalTime stop = new LocalTime( inputStop );
LocalTime now = LocalTime.now();
// Comparing using Half-Open logic, where beginning is inclusive and ending is exclusive.
boolean isNowContainedWithinInterval = ( ( now.isEqual( start ) ) || ( now.isAfter( start ) ) ) && ( now.isBefore( stop ) );
Dump to console…
System.out.println( "start: " + start );
System.out.println( "stop: " + stop );
System.out.println( "now: " + now );
System.out.println( "isNowContainedWithinInterval: " + isNowContainedWithinInterval );
When run…
start: 09:00:00.000
stop: 17:30:00.000
now: 12:42:06.567
isNowContainedWithinInterval: true
In the real-world, I would add an assertion test proving the stop time is later than the start time, to validate inputs.
there is a form having a drop down for country ,user will select the country ,then there is a drop down for time zone ,user will select the time zone which are available in country selected by the user.Then user will enter the local date( eg: 26-Dec-2014) and time( 23:11)(24 hours time) this entered date and time is for the selected country and time zone.
now i have to convert this date and time to GMT time zone. how can i do this using joda time
how the daylight saving time(DST) will be calculate?
i have made a function which accepts the parameters as from time zone,to time zone,date
public static String convertTimeZones( String fromTimeZoneString,
String toTimeZoneString, String fromDateTime) {
DateTimeZone fromTimeZone = DateTimeZone.forID(fromTimeZoneString);
DateTimeZone toTimeZone = DateTimeZone.forID(toTimeZoneString);
DateTime dateTime = new DateTime(fromDateTime, fromTimeZone);
DateTimeFormatter outputFormatter
= DateTimeFormat.forPattern("dd-MMM-yyyy HH:mm").withZone(toTimeZone);
return outputFormatter.print(dateTime);
}
i want to pass the date to this function in a format (24-Feb-2014 12:34) but it is not taking this format
//so we can get the local date
//UTC = true, translate from UTC time to local
//UTC = false, translate from local to UTC
public static String formatUTCToLocalAndBackTime(String datetime, boolean UTC) {
String returnTimeDate = "";
DateTime dtUTC = null;
DateTimeZone timezone = DateTimeZone.getDefault();
DateTimeFormatter formatDT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
DateTime dateDateTime1 = formatDT.parseDateTime(datetime);
DateTime now = new DateTime();
DateTime nowUTC = new LocalDateTime(now).toDateTime(DateTimeZone.UTC);
long instant = now.getMillis();
long instantUTC = nowUTC.getMillis();
long offset = instantUTC - instant;
if (UTC) {
//convert to local time
dtUTC = dateDateTime1.withZoneRetainFields(DateTimeZone.UTC);
//dtUTC = dateDateTime1.toDateTime(timezone);
dtUTC = dtUTC.plusMillis((int) offset);
} else {
//convert to UTC time
dtUTC = dateDateTime1.withZoneRetainFields(timezone);
dtUTC = dtUTC.minusMillis((int) offset);
}
returnTimeDate = dtUTC.toString(formatDT);
return returnTimeDate;
}
Java time api is better compared to joda time api when it comes to various timezones, specially with day light savings
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
LocalDateTime start = LocalDateTime.of(2021, 02, 25, 14, 25, 00);
ZoneId zone = ZoneId.of("Asia/Singapore");
start = start.atZone(zone).withZoneSameInstant(ZoneOffset.UTC).toLocalDateTime();
I just wanted to find date parameter is current date (yyyy-MM-dd) without using simpledateformater or any date to string convertion and then find is equals.
specifiedDate=2012-12-20
currentDate=2012-12-21
specifiedDate == currentDate
to be simple i dont want time (i.e HH:mm:S) not to be included while validating
i have tried something like
public boolean isCurrentDate(Calendar date){
Calendar currentDate = Calendar.getInstance().getTime();
if (currentDate.getDate()==(date.getTime().getDate())
&& currentDate.getMonth()==(date.getTime().getMonth())
&& currentDate.getYear()==(date.getTime().getYear()) )
{
return true;
}
return false;
}
please suggest a better way or if any libraries already available for this !!
What about setting time fields to 0 before comparing
currentDate.set(Calendar.HOUR_OF_DAY, 0);
currentDate.set(Calendar.MINUTE, 0);
currentDate.set(Calendar.SECOND, 0);
currentDate.set(Calendar.MILLISECOND, 0);
Try this if you want to do only
1) Using strings
String s1 = new String("2012-01-27");
String s2 = new String("2011-01-28");
System.out.println(s1.compareTo(s2));
The result will be TRUE if s1 is "bigger" than s2 in lexicographical way and it's what you need. To get more info read javadoc for compareTo() method.
2) Using Joda Time
Using Joda Time lib you can acheive as below
DateTime first = ...;
DateTime second = ...;
LocalDate firstDate = first.toLocalDate();
LocalDate secondDate = second.toLocalDate();
return firstDate.compareTo(secondDate);
I prefer second option
If you are using calendar
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The dates must not be null");
}
return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) &&
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) &&
cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR));
}
public static boolean isToday(Calendar cal) {
return isSameDay(cal, Calendar.getInstance());
}
If you are using Date
public static boolean isSameDay(Date date1, Date date2) {
if (date1 == null || date2 == null) {
throw new IllegalArgumentException("The dates must not be null");
}
Calendar cal1 = Calendar.getInstance();
cal1.setTime(date1);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
return isSameDay(cal1, cal2);
}
public static boolean isToday(Date date) {
return isSameDay(date, Calendar.getInstance().getTime());
}
Your last line && currentDate.getYear()==(date.getMonth()) ) appears to be comparing the year and month not the year and year. Could this be your issue?
Try this:
currentDate.set(Calendar.DATE, 0);
Time Zone
The example code in your question ignores the crucial issue of time zone. The date, that is the beginning and ending points of a day, is defined by a time zone.
Both java.util.Calendar and java.util.Date have no time zone assigned. They represent a date and a time in UTC/GMT.
So you need to apply a desired time zone, relevant to the context of your app & data. That means you need a decent date-time library. Something other than java.util.Date/Calendar, java.text.SimpleDateFormat and their sibling classes, as they are notoriously troublesome. Use either Joda-Time or the new java.time.* package bundled with Java 8 (inspired by Joda-Time, defined by JSR 310).
Note the use of the method withTimeAtStartOfDay. That gets the first moment of the day. That is usually the time 00:00:00 but not always. Daylight Saving Time (DST) or other anomalies may produce a different time. That method smartly handles such issues.
Today = Span of Time
Technically, when working with date-time values, a particular "date" is actually a span of time. The most common and generally useful way to define that span is "half-open" where the beginning is inclusive and the ending is exclusive. That means, for current date, we want the first moment of today (inclusive) to the first moment of tomorrow (exclusive). Then we ask if the target date-time falls within that span.
There are other ways to get this job done. I'm showing this approach because it is applies to situations beyond the question of "today".
Joda-Time
Joda-Time offers three classes for defining a span of time: Interval, Period, and Duration.
Example Code
Setup our input data, a Calendar object.
// Create a Calendar object to simulate input.
java.util.Date date = DateTime.now().minusDays( 3 ).toDate();
java.util.Calendar cal = java.util.Calendar.getInstance();
cal.setTime( date );
Define "today" as a span of time, and see if target date-time falls within that span.
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeInQuestion = new DateTime( cal.getTimeInMillis(), timeZone );
DateTime now = new DateTime( timeZone );
Interval today = new Interval( now.withTimeAtStartOfDay(), now.plusDays( 1 ).withTimeAtStartOfDay() );
boolean isDateTimeInQuestionInInterval = today.contains( dateTimeInQuestion );
Dump to console…
System.out.println( "cal: " + cal.getTime() );
System.out.println( "dateTimeInQuestion: " + dateTimeInQuestion );
System.out.println( "now: " + now );
System.out.println( "today: " + today );
System.out.println( "isDateTimeInQuestionInInterval: " + isDateTimeInQuestionInInterval );
When run…
cal: Wed Feb 12 22:46:04 PST 2014
dateTimeInQuestion: 2014-02-13T12:16:04.369+05:30
now: 2014-02-16T12:16:04.497+05:30
today: 2014-02-16T00:00:00.000+05:30/2014-02-17T00:00:00.000+05:30
isDateTimeInQuestionInInterval: false
I'm receiving a datetime from a SOAP webservice without timzone information. Hence, the Axis deserializer assumes UTC. However, the datetime really is in Sydney time. I've solved the problem by substracting the timezone offset:
Calendar trade_date = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
long millis = trade_date.getTimeInMillis() - est_tz.getRawOffset();
trade_date.setTimeZone( est_tz );
trade_date.setTimeInMillis( millis );
However, I'm not sure if this solution also takes daylight saving into account. I think it should, because all operations are on UTC time. Any experiences with manipulating time in Java? Better ideas on how to solve this problem?
I pity the fool who has to do dates in Java.
What you have done will almost certainly go wrong around the daylight savings transitions. The best way to to it is probably to create a new Calendar object, set the Timezone on it, and then set all of the fields individually, so year, month, day, hour, minute, second, getting the values from the Date object.
Edit:
To keep the everyone happy, you should probably do this:
Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
Calendar sydneyTime = Calendar.getInstance(TimeZone.getTimeZone("Australia/Sydney");
utcTime.setTime(trade_date);
for (int i = 0; i < Calendar.FIELD_COUNT; i++) {
sydneyTime.set(i, utcTime.get(i));
}
Then you won't be using any deprecated methods.
I want to thank the person for responce 6. This was a great start for me and an approach I did not consider. There are some addtional steps required to bring it to production code level. In particular observe the steps required for DST_OFFSET and ZONE_OFFSET. I want to share the solution I came up with.
This takes the time from the input Calendar object, copies it to the output time, sets the new time zone to the output. This is used when taking time literally from the database and setting the Time Zone without changing the time.
public static Calendar setNewTimeZoneCopyOldTime( Calendar inputTime,
TimeZone timeZone ) {
if( (inputTime == null) || (timeZone == null) ) { return( null ); }
Calendar outputTime = Calendar.getInstance( timeZone );
for( int i = 0; i < Calendar.FIELD_COUNT; i++ ) {
if( (i != Calendar.ZONE_OFFSET) && (i != Calendar.DST_OFFSET) ) {
outputTime.set(i, inputTime.get(i));
}
}
return( (Calendar) outputTime.clone() );
}
However, I'm not sure if this solution
also takes daylight saving into
account. I think it should, because
all operations are on UTC time.
Yes, you should take the daylight saving into account, since it affects the offset to UTC.
Any experiences with manipulating time in Java? Better ideas on how to solve this problem?
Joda-Time is a better time API. Maybe the following snippet could be of help :
DateTimeZone zone; // TODO : get zone
DateTime fixedTimestamp = new DateTime(year, monthOfYear, dayOfMonth, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond, zone);
JodaTime types are immutable which is also a benefit.
I normally do it this way
Calendar trade_date_utc = trade.getTradeDateTime();
TimeZone est_tz = TimeZone.getTimeZone("Australia/Sydney");
Calendar trade_date = Calendar.GetInstance(est_tz);
trade_date.setTimeInMillis( millis );
Are you getting an ISO 8601 style string from that messed-up Web Service? If so, the Joda-Time 2.3 library makes this very easy.
If you are getting an ISO 8601 string without any time zone offset, you pass a time zone object to the DateTime constructor.
DateTimeZone timeZone = DateTimeZone.forID( "Australia/Sydney" );
String input = "2014-01-02T03:00:00"; // Note the lack of time zone offset at end.
DateTime dateTime = new DateTime( input, timeZone );
Dump to console…
System.out.println( "dateTime: " + dateTime );
When run…
dateTime: 2014-01-02T03:00:00.000+11:00
#Test
public void tzTest() {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS Z");
TimeZone tz1 = TimeZone.getTimeZone("Europe/Moscow");
Calendar cal1 = Calendar.getInstance(tz1);
long l1 = cal1.getTimeInMillis();
df.setTimeZone(tz1);
System.out.println(df.format(cal1.getTime()));
System.out.println(l1);
TimeZone tz2 = TimeZone.getTimeZone("Africa/Douala");
Calendar cal2 = Calendar.getInstance(tz2);
long l2 = l1 + tz1.getRawOffset() - tz2.getRawOffset();
cal2.setTimeInMillis(l2);
df.setTimeZone(tz2);
System.out.println(df.format(cal2.getTime()));
System.out.println(l2);
assertNotEquals(l2, l1);
}
Running CalendarTest
2016-06-30 19:09:16.522 +0300
1467302956522
2016-06-30 19:09:16.522 +0100
1467310156522
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.137 sec
I've decided to reparse the datetime string received with the correct time zone set. This should also consider daylight saving:
public class DateTest {
private static SimpleDateFormat soapdatetime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
/**
* #param args
*/
public static void main(String[] args) {
TimeZone oztz = TimeZone.getTimeZone("Australia/Sydney");
TimeZone gmtz = TimeZone.getTimeZone("GMT");
Calendar datetime = Calendar.getInstance( gmtz );
soapdatetime.setTimeZone( gmtz );
String soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
soapdatetime.setTimeZone( oztz );
datetime.setTimeZone( oztz );
try {
datetime.setTime(
soapdatetime.parse( soap_datetime )
);
} catch (ParseException e) {
e.printStackTrace();
}
soapdatetime.setTimeZone( gmtz );
soap_datetime = soapdatetime.format( datetime.getTime() );
System.out.println( soap_datetime );
}
}