Calulate minutes until midnight in Java in a linux environment - java

Take a look at the following commands:
$ sudo ln -fs /usr/share/zoneinfo/US/Pacific localtime
$ date
Mon Oct 13 15:29:02 PDT 2014
$ sudo ln -fs /usr/share/zoneinfo/US/Hawaii localtime
$ date
Mon Oct 13 12:29:20 HST 2014
That is all well and good. Now I have some software written in java that needs to know how many minutes until midnight so it can perform some maintenance.
Here is the code I came up with:
// Time to perform maintenance
String rawTime = "23:59";
int hours = Integer.parseInt(rawTime.substring(0, 2));
int minutes = Integer.parseInt(rawTime.substring(3, 5));
// Get current Time
Calendar c = Calendar.getInstance();
long now = c.getTimeInMillis();
Date dateNow = new Date(now);
System.out.println(new Date(now));
// Get midnight
c.set(Calendar.HOUR_OF_DAY, hours);
c.set(Calendar.MINUTE, minutes);
c.set(Calendar.SECOND, 0);
c.set(Calendar.MILLISECOND, 0);
Date midnight = new Date(c.getTimeInMillis());
// Get Difference
System.out.println(String.format("Calc minutes from %s to %s", dateNow, midnight));
long result = ((midnight.getTime()/60000) - (dateNow.getTime()/60000));
System.out.println((int) result);
Output when linux is set to Hawaii time zone:
Calc minutes from Mon Oct 13 15:36:51 PDT 2014 to Mon Oct 13 23:59:00 PDT 2014
Result: 503
As you can see, I'm not getting the correct time... I'm getting PDT instead of HST. I'm not that concerned with why toString() of a date returns PDT since it is time zone independent but I am concerned with how I should calculate this?
Let's just start with '11:59' calculate how many minutes until '11:59' for whatever linux thinks the time is...I am open to a solution where I set the linux time in a different fashion.
Thanks! this should be this hard...

The java.util.Date and .Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time or the new java.time package in Java 8.
In both Joda-Time and java.time, a date-time object truly knows its own assigned time zone (unlike java.util.Date).
Here is some example code in Joda-Time 2.5.
DateTimeZone timeZoneHawaii = DateTimeZone.forID( "Pacific/Honolulu" );
DateTime now = DateTime.now( timeZoneHawaii );
DateTime dayStart = now.plusDays(1).withTimeAtStartOfDay(); // Usually 00:00:00.000 but not always because of Daylight Saving Time or possibly other anomalies.
int minutesUntilDayStartsInHawaii = Minutes.minutesBetween( now, dayStart ).getMinutes();

Related

Convert a specific time in one timezone to another timezone [duplicate]

This question already has answers here:
Timezone conversion
(13 answers)
Closed 1 year ago.
I'm trying to convert the hour 8:00am EST (America/New_York), to display in whatever time that would be on the users system default zone. The date is not needed, only the time. I have been searching and I can only find ways to convert the current time.
You need to use ZonedDateTime and display only time part using DateTimeFormatter. Something like this:
//assuming the server is in US
ZoneId serverZone = ZoneId.of("US/Eastern");
ZoneId userZone = ZoneId.of("Asia/Tokyo");
ZonedDateTime nyTime = ZonedDateTime.now(serverZone);
ZonedDateTime userTime = nyTime.withZoneSameInstant(userZone);
String pattern = "hh:mm a z VV";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(pattern);
System.out.println("Server time: " + dtf.format(nyTime));
System.out.println("User time: " + dtf.format(userTime));
Output:
Server time: 08:29 AM EDT US/Eastern
User time: 09:29 PM JST Asia/Tokyo
For the sake of the example I am assuming that you want to convert today at 8 AM EDT to the user’s default time zone. Without a date we cannot perform the conversion correctly. Like onkar ruikar in the other answer I am using and recommending java.time, the modern Java date and time API, for all of your time work.
ZoneId sourceZone = ZoneId.of("America/New_York");
ZoneId targetZone = ZoneId.systemDefault();
LocalTime sourceTime = LocalTime.of(8, 0);
ZonedDateTime sourceDateTime = ZonedDateTime.now(sourceZone).with(sourceTime);
ZonedDateTime targetDateTime = sourceDateTime.withZoneSameInstant(targetZone);
LocalTime targetTime = targetDateTime.toLocalTime();
System.out.println(targetTime);
Output when I ran today in America/Sao_Paulo time zone:
09:00
At this time of year (September), North American Eastern Time is at UTC offset -04:00 in most places including New York, and São Paulo is at -03:00, so 1 hour has been added to the time.
If instead I run the code in December, the output will be:
11:00
By then New York will be at offset -05:00 and São Paulo at -02:00 due to summer time, so 3 hours need to be added.
Link
Oracle tutorial: Date Time explaining how to use java.time.

Inconsistency in handling date and time in Java

I have noticed strange behavior of date and time in java. I have the following code:
public class TestDateTime {
public static void main(String[] args) {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Helsinki"));
Calendar calendar = GregorianCalendar.getInstance();
assert(calendar.getTimeZone().equals(TimeZone.getDefault()));
//Set 1899-12-30T23:00:00
calendar.set(1899,11,30,23,0,0);
calendar.set(Calendar.MILLISECOND,0);
long timeInMillis = calendar.getTimeInMillis();
java.util.Date calendarDateTime = new java.util.Date(timeInMillis);
LocalDateTime localDateTime = LocalDateTime.ofInstant(ofEpochMilli(timeInMillis), ZoneId.systemDefault());
System.out.println("Time in millis: " + timeInMillis);
System.out.println("Date: " + calendarDateTime.toString());
System.out.println("Local DateTime: " + localDateTime.toString());
}
}
The output is:
Time in millis: -2209086000000
Date: Sat Dec 30 23:00:00 EET 1899
Local DateTime: 1899-12-30T22:39:49
timeInMillis must contain the number of milliseconds passed from 1970-01-01T00:00:00Z.
The instance of Date class stores number of milliseconds passed from 1970-01-01T00:00:00Z.
Date.toString() method returns local date and time for the default timezone.
So the Date.toString() and LocalDateTime.toString() must return the same date and time, but we see the difference (more than 20 minutes).
Is this a bug of java, or I use date and time incorrectly in Java?
This is a weirdness caused by Finland time change, see Clock Changes in Helsinki, Finland (Helsingfors) in 1921:
May 1, 1921 - Time Zone Change (HMT → EET)
When local standard time was about to reach
Sunday, May 1, 1921, 12:00:00 midnight clocks were turned forward 0:20:11 hours to
Sunday, May 1, 1921, 12:20:11 am local standard time instead
Those 20 minutes 11 seconds seem to be what you're observing.
As Jim Garrison said in his answer, LocalDateTime is correctly handling that, while Calendar is not.
In reality, it seems that the old TimeZone is getting the offset wrong, while the new ZoneId is getting it right, as can be seen in the following test code:
public static void main(String[] args) {
compare(1800, 1, 1, 0, 0, 0);
compare(1899,12,31, 23,59,59);
compare(1900, 1, 1, 0, 0, 0);
compare(1900,12,30, 23, 0, 0);
compare(1921, 4,30, 0, 0, 0);
compare(1921, 5, 1, 0, 0, 0);
compare(1921, 5, 2, 0, 0, 0);
}
private static void compare(int year, int month, int day, int hour, int minute, int second) {
Calendar calendar = new GregorianCalendar();
calendar.clear();
calendar.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
calendar.set(year, month-1, day, hour, minute, second);
Date date = calendar.getTime();
ZonedDateTime zdt = ZonedDateTime.of(year, month, day, hour, minute, second, 0, ZoneId.of("Europe/Helsinki"));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z XXX");
sdf.setTimeZone(TimeZone.getTimeZone("Europe/Helsinki"));
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss z XXX");
System.out.printf("%04d-%02d-%02d %02d:%02d:%02d %s = %d %s = %d %d%n",
year, month, day, hour, minute, second,
sdf.format(date), date.getTime(),
dtf.format(zdt), zdt.toInstant().toEpochMilli(),
date.getTime() - zdt.toInstant().toEpochMilli());
}
Output
1800-01-01 00:00:00 1800-01-01 00:00:00 EET +02:00 = -5364669600000 1800-01-01 00:00:00 EET +01:39 = -5364668389000 -1211000
1899-12-31 23:59:59 1899-12-31 23:59:59 EET +02:00 = -2208996001000 1899-12-31 23:59:59 EET +01:39 = -2208994790000 -1211000
1900-01-01 00:00:00 1900-01-01 00:00:00 EET +02:00 = -2208996000000 1900-01-01 00:00:00 EET +01:39 = -2208994789000 -1211000
1900-12-30 23:00:00 1900-12-30 23:00:00 EET +01:39 = -2177548789000 1900-12-30 23:00:00 EET +01:39 = -2177548789000 0
1921-04-30 00:00:00 1921-04-30 00:00:00 EET +01:39 = -1536025189000 1921-04-30 00:00:00 EET +01:39 = -1536025189000 0
1921-05-01 00:00:00 1921-05-01 00:20:11 EET +02:00 = -1535938789000 1921-05-01 00:20:11 EET +02:00 = -1535938789000 0
1921-05-02 00:00:00 1921-05-02 00:00:00 EET +02:00 = -1535853600000 1921-05-02 00:00:00 EET +02:00 = -1535853600000 0
LocalDateTime is CORRECT. According to the TZ database, the GMT offset at that date was 1:39:49:
# Zone NAME GMTOFF RULES FORMAT [UNTIL]
Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31
1:39:49 - HMT 1921 May # Helsinki Mean Time
2:00 Finland EE%sT 1983
2:00 EU EE%sT
Historical timezones are incredibly complex, and prior to standardization offsets were inherited from settings based on things like mean solar noon. When going back that far just about any offset is possible, and the IANA TZ database is the master reference for historical data.
From what I can see in the database, the weird offset did not get standardized to 2:00:00 until 1921 when HMT was replaced with EE(S)T.
As others pointed out, the difference is because the LMT (local mean time) value is not being taken into account by the Date object. This has been discussed before here, with regard to Joda-Time - the precursor to Java 8's time package.
Additionally, the Joda-Time FAQ says the following:
Why is the offset for a time-zone different to the JDK?
There are two main reasons for this.
The first reason is that both the JDK and Joda-Time have time-zone
data files. It is important to keep both up to date and in sync if you
want to compare the offset between the two.
The second reason affects date-times before the modern time-zone
system was introduced. The time-zone data is obtained from the
time-zone database. The database contains information on "Local Mean
Time" (LMT) which is the local time that would have been observed at
the location following the Sun's movements.
Joda-Time uses the LMT information for all times prior to the first
time-zone offset being chosen in a location. By contrast, the JDK
ignores the LMT information. As such, the time-zone offset returned by
the JDK and Joda-Time are different for date-times before the modern
time-zone system.
The last part (which I bolded) is relavent to both Joda-Time and Java 8, even though Java 8 has one set of time zone data files (unlike Joda-Time).
To be more precise about API-inconsistency:
While the new java.time-API always uses the LMT-informations of TZDB, we have also to state that the old JDK-class java.util.TimeZone makes a cut in year 1900 with the consequence that LMT-informations are not taken into account before the year 1900, but after 1900, yes, it is still taken into account! Just make your experiments with an appropriate zone... (Asia/Kamchatka for example)
We cannot really say that either the LMT-strategy of java.time-API is correct or the traditional 1900-strategy. Keep also in mind that there is an open JDK-issue to abolish the LMT-strategy. Citation:
The current TimeZone code does not use LMT. Joda-Time does, as does
JSR-310. This is wrong.
Recent discussion on the tzdb mailing list has indicated that the data
is not properly maintained or reliably linked to the city of the zone
ID. It is also relatively meaningless, being a notional value for a
single city within a large region.
Removing LMT is a good thing.
And Xueming Shen from Oracle says as comment in this issue:
The current j.u.TimeZone implementation DOES use LMT. If the LMT is
defined/used cross the 1900.1.1 j.u.TimeZone cutoff date (by the tzdb
data). For example the offset for Asia/Kamchatka from 1900.1.1 to the
1922.11.10 will be the LMT 10.34.36. Yes, if the LMT end date is before 1900.1.1, the LMT will not be used by the j.u.TZ.
As additional historical note, the JDK-issue was originally suggested by the main author of java.time-API S. Colebourne, see also the ancestor on threeten-issue-tracker.

Calendar DATE field is not updated

I'm working on some code that takes care of timezone differences (in this case, converting a date from UTC to EST/EDT) and I noticed that I'm getting the incorrect DATE field from the Calendar variable.
Here are the log excerpts from the timezone change:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
The code is correctly updating the time to the 14th, based on what shows up with Calendar.getTime(), but when I call Calendar.get(Calendar.DATE), I'm still getting 15 as the date.
Why are the fields not updating when the time itself is?
Code excerpt:
Calendar cal = Calendar.getInstance();
cal.setTime(new Date());
TimeZone fromTz = TimeZone.getTimeZone("UTC");
TimeZone toTz = TimeZone.getTimeZone("America/New_York");
jlog.info(fromTz.getID() + " time: " + cal.getTime().toString());
cal.setTimeZone(fromTz);
// Finds the difference between the two timezones based on their offset from UTC (in the case of the system timezone changing in the future).
long currentTime = System.currentTimeMillis();
int timeDifference = toTz.getOffset(currentTime) - fromTz.getOffset(currentTime);
cal.add(Calendar.MILLISECOND, timeDifference);
if (dst) { // Logic for determining whether or not the extra hour for DST is needed.
cal.add(Calendar.MILLISECOND, fromTz.getDSTSavings());
}
jlog.info(toTz.getID() + " time: " + cal.getTime().toString());
jlog.info(cal.getTime().toString() + " - " + cal.get(Calendar.DATE));
Output for the above code:
UTC time: Fri Nov 15 00:28:44 EST 2013
America/New_York time: Thu Nov 14 19:28:44 EST 2013
Thu Nov 14 19:28:44 EST 2013 - 15
NOTE: Please don't suggest that I use Joda-time. I'm just looking for an answer to this question as is.
If it's not solvable because Calendar/Date are terrible packages, that's fine - I'll just parse the date myself to get the correct values. Thanks in advance.
You haven't shown us enough code to know what's going on, but your output is very easy to explain: you're calling Date.toString() which always formats the instant in time using the system local time zone. The time zone in the Calendar object is irrelevant.
So it looks like your Calendar may be in UTC for example, in which case the day is 15.
Note that the first line of your log is clearly nonsense:
UTC time: Fri Nov 15 00:28:44 EST 2013
It's either UTC or it's EST. It can't be both.
It's not clear where your data comes from or exactly how you're dealing with it, but if you're manually adjusting the date/time by adding or subtracting parts, you're almost certainly doing it wrong. It's very important to understand that a java.util.Date doesn't have any notion of a time zone as part of its data - it's just an instant in time.
To format a Date in a particular time zone, you'd usually use a SimpleDateFormat and specify the time zone on that. For example:
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println("The time in New York is " + format.format(new Date()));
EDIT: Now that we've seen your code, you should definitely not do things that way. You're adjusting the point in time, which isn't what you want - you only want to change your view on the same point in time, which can be achieved using Calendar.setTimeZone to change what's returned by Calendar.get, and using DateFormat.setTimeZone to change which time zone is used for parsing/formatting text.
java.time
The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.
Solution using java.time, the modern Date-Time API:
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdtUtc = ZonedDateTime.of(LocalDate.of(2013, 11, 15), LocalTime.of(0, 28, 44),
ZoneId.of("Etc/UTC"));
ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
// Custom format
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z uuuu", Locale.ENGLISH);
System.out.println(zdtNewYork.format(dtf));
}
}
Output:
2013-11-14T19:28:44-05:00[America/New_York]
Thu Nov 14 19:28:44 EST 2013
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
If I understand your question, you could do it with something like this -
Calendar c = Calendar.getInstance();
DateFormat formatter = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy",
Locale.ENGLISH);
formatter.setTimeZone(TimeZone.getTimeZone("UTC")); // <-- Set the timezone on the
// DateFormat
/* Your input date/time */
c.setTime(new GregorianCalendar(2013, 10, 15, 0, 28, 44).getTime());
System.out.println(formatter.format(c.getTime()));
c.setTimeZone(TimeZone.getTimeZone("EST"));
System.out.println(c.getTime());
The output of this code is
Fri Nov 15 05:28:44 UTC 2013
Fri Nov 15 00:28:44 EST 2013

Calendar.getTime() not returning UTC date if TimeZone is defined

I have done this for my Calendar instance to return Date in UTC timezone:
SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:SS Z");
TimeZone tz = TimeZoneUtil.getTimeZone(StringPool.UTC);
formatter.setTimeZone(tz);
Date dtStart = null;
Date dtEnd = null;
try{
dtStart = formatter.parse(formatter.format(startDate.getTime()));
dtEnd = formatter.parse(formatter.format(endDate.getTime()));
}catch (Exception e) {
e.getStackTrace();
}
It works fine till I format calendar timestamp to return a string date with required timezone but when I parse that string date to Date date, it again picks up local timezone?
I need to store Date object in UTC timezone.
Any help will be highly appreciated!
You can use this:
Date localTime = new Date();
//creating DateFormat for converting time from local timezone to GMT
DateFormat converter = new SimpleDateFormat("dd/MM/yyyy:HH:mm:ss");
//getting GMT timezone, you can get any timezone e.g. UTC
converter.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println("local time : " + localTime);;
System.out.println("time in GMT : " + converter.format(localTime));
It will give:
local time: Fri Jun 21 11:55:00 UTC 2013
time in GMT : 21/06/2013:11:55:00
I hope it will help.
Cheers.
Date object in java will always store the values in the host machine (your system) time zone information.
This is from javadoc :
Although the Date class is intended to reflect coordinated universal time (UTC), it may not do so exactly, depending on the host environment of the Java Virtual Machine.
You should trying using Joda Time which is much advanced.
Instead of setting TimeZone in multiple places, it is a good idea to set timezone using -Duser.timezone=GMT or PST.
And, you can easily test how Java deals with timezone and getTime() ignores timezone with an actual example:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ"); // print with timezone
TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("GMT"));
TimeZone.setDefault(timeZone); // set system timezone as GMT
sdf.setTimeZone(timeZone); // formatter also has a timezone
Date date = new Date();
System.out.println(date); // system says GMT date
System.out.println(date.getTime()); // only prints time in milliseconds after January 1, 1970 00:00:00 GMT
System.out.println(sdf.format(date));
timeZone = TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles"));
TimeZone.setDefault(timeZone); // set system timezone as GMT
sdf.setTimeZone(timeZone); // formatter also has a timezone
date = new Date();
System.out.println(date);
System.out.println(date.getTime()); // prints the same value as above, "not including timezone offset"
System.out.println(sdf.format(date));
// GMT and PDT times are same as getTime() only returns time in ms since UTC for the day ignoring timezone which is mostly used for formatting
Wed Mar 14 22:43:43 GMT 2018
1521067423108
2018-03-14T22:43:43+0000
Wed Mar 14 15:43:43 PDT 2018
1521067423125 // not includes timezone in getTime()
2018-03-14T15:43:43-0700 // formatting looks fine
The good explanation of why Date object taking Current time zone value ,
please refer this SO answer
EDIT.
here I am gonna add some important part of that answers.
java.util.Date is has no specific time zone, although its value is most commonly thought of in relation to UTC. What makes you think it's in local time?
To be precise: the value within a java.util.Date is the number of milliseconds since the Unix epoch, which occurred at midnight January 1st 1970, UTC. The same epoch could also be described in other time zones, but the traditional description is in terms of UTC. As it's a number of milliseconds since a fixed epoch, the value within java.util.Date is the same around the world at any particular instant, regardless of local time zone.

Get server date problem

I have problem with getting server date (linux server). When I use linux 'date' command I get properly date value (real date). If I modify some file
on server, modify date is also properly (real date). But if i use java code System.out.println(new Date()) on server I get date with 1 hour difference
i.e. linux 'date' command result = Wed Sep 16 08:48:25 CEST, System.out.println(new Date()) result = Wed Sep 16 07:48:25 GMT+1
Is this linux configuration problem or wrong getting date using java.
Thanks
date --rfc-2822; date +%s
Wed, 16 Sep 2009 09:59:36 +0200
1253087976
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
16 wrz 2009 09:00:33 +0100
1253088033
You must make sure you use the correct time zone before using Date (or Calendar, for that matter - wasn't Date deprecated?).
For instance:
/* Skipping the boring class def part. */
public static void main(String[] args) {
Date date = new Date();
DateFormat myDateFormat = new SimpleDateFormat();
TimeZone firstTime = TimeZone.getTimeZone(args[0]);
myDateFormat.setTimeZone(firstTime);
System.out.println("-->"+args[0]+": " + myDateFormat.format(date));
}
the argument then can be your desired time zone, for example "IST", "GMT", or whatever.
This is probably a timezone/daylight savings issue. Use:
java.util.Timezone.getDefault()
to see which timezone is Java configured to use and whether daylight savings apply or not.
I suggest you upgrade your Java installation. Your JRE likely doesn't have the latest daylight savings rules in place. Java gets the time since the epoch, and uses your current TZ setting to compute what the local time is. DST rules change from time to time, and both the operating system and the JDK need to be updated when this occurs.
Can you add the output of the following to your question:
# unix
date --rfc-2822; date +%s
# Java
System.out.println(new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z").format(new Date()));
System.out.println(new Date().getTime() / 1000);
The should both output something like:
Wed, 16 Sep 2009 17:26:08 +1000
1253085968

Categories