Time Difference with UTC java - java

I want convert the Date in long. But the hours are incorrectly calculated at pc. On Android emulator is the Time correct calculated(on emulator is UTC time). Please help
String time = "15:54";
Date date = new Date();
date.setHours(Integer.parseInt(time.substring(0, 2)));
long Hours = (date.getTime() / (1000 * 60 * 60)) % 24;
System.out.print(Hours); // 14
System.out.print("\n" + date.getHours()); // 15

When you are setting the hours to Date, java.util.Date object is independent of the concept of TimeZone. Per its javadoc here,
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.
Hence, when you set your hours to 15, date interprets your own timezone and sets the hours to it. If there is a difference in UTC (the result you expect) and your current timezone, that difference is being reflected in your case above (14 vs 15).
To solve it, 1 option is to explicitly bring your own timezone to UTC and match the expected results:
String time = "15:54";
Date date = new Date();
java.util.TimeZone.setDefault(TimeZone.getTimeZone("UTC")); // ADDED THIS LINE
date.setHours(Integer.parseInt(time.substring(0, 2)));
long hours = (date.getTime() / (60 * 60 * 1000)) % 24;
System.out.print(hours); // NOW THIS GIVES 15
System.out.print("\n" + date.getHours()); // 15
The other option would to use Calendar class (if not jodatime) in case you want to accurately interpret the TimeZone related results.

Your question is not clear.
This kind of date-time work is much easier with the Joda-Time library.
Relying on the default time zone is troublesome. Instead, specify your time zone. It sounds like in your case the desired hour "15" is in UTC/GMT (no time zone offset). So, specify UTC.
What did you mean by "convert the Date in long"? Perhaps you meant get the milliseconds-since-epoch stored inside the Date (and in Joda-Time DateTime).
DateTime now = new DateTime( DateTimeZone.UTC );
DateTime fifteen = now.withHourOfDay( 15 );
Dump to console…
System.out.println( "now: " + now );
System.out.println( "fifteen: " + fifteen );
System.out.println( "fifteen in millis: " + fifteen.getMillis() );
System.out.println( "fifteen's hour-of-day: " + fifteen.getHourOfDay() );
When run…
now: 2014-02-14T12:43:00.836Z
fifteen: 2014-02-14T15:43:00.836Z
fifteen in millis: 1392392580836
fifteen's hour-of-day: 15

If try to call method:
private static String TIME_FORMAT = "HH:mm Z";
public static void TestDate( String time_ ) throws ParseException
{
SimpleDateFormat format = new SimpleDateFormat( TIME_FORMAT );
Date date = format.parse( time_ );
long hours = (date.getTime() / (1000 * 60 * 60)) % 24;
System.out.println( "The value 'hours' for '" + time_ + "' is '" + Long.toString( hours ) + "'" );
}
with "15:54 UTC", output wil be:
The value 'hours' for '15:54 UTC' is '15'

Related

How to convert UTC time to local time in android for sunset time

I am trying to get the sunset time for the users in there local time. I get the sunset time in UTC from sunrise-sunset.org. Then I convert it to local time, then I account for daylight savings time and then I convert it to regular time.
The problem is it comes out hours off.
Edited
For example:
In the app the user can set there location to anywhere in the world, let's say they set it to Springfield MO(USA). It returns 04:57:31 AM, after I convert it and what not it comes out to 5:57 AM, even though it should say 4:57 PM. That is for API 30.
Now what makes that even more strange is if I use a API 22 phone it comes out as 7:57 PM.
I needed to support API 21 to API 30(Android 11).
Also it keeps returning daylight savings time as on, when it's not.
public void RequestSunsetTime(String lat, String lng){
// set loading text
sunsetTimeTextView.setText(R.string.loading_text);
ProjectRepository projectRepository = new ProjectRepository();
String url = "https://api.sunrise-sunset.org/json?lat=" + lat + "&lng=" + lng + "&date=today";
projectRepository.requestDataPartTwo(url, new ProjectRepository.VolleyResponseListenerForTwo() {
#Override
public void onResponse(String UTCtime) {
// convert utc time to local time
String time = UTCtime;
System.out.println("== TIME ==" + time);
try {
SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss a", Locale.ENGLISH);
df.setTimeZone(TimeZone.getTimeZone("UTC"));
Date _date = df.parse(UTCtime);
df.setTimeZone(TimeZone.getDefault());
System.out.println(">>>>>>>>>>> Time zone: " + TimeZone.getDefault());
time = df.format(_date);
System.out.println(">>>>>>>>>>> time: " + time);
// convert army time to standard time
String[] timeParts = time.split(":"); // convert to array
// fetch
int hours = Integer.parseInt(timeParts[0]);
System.out.println(">>>>> army time hours: " +hours);
int minutes = Integer.parseInt(timeParts[1]);
// --- *.getDSTSavings()* adds time for day light saving time
int timeForDST = (((TimeZone.getDefault().getDSTSavings() / 1000) / 60) / 60);
System.out.println(">>>>>>>>>>> time: " + time);
// calculate
String timeValue = "";
if (hours > 0 && hours <= 12) {
timeValue= "" + hours;
} else if (hours > 12) {
timeValue= "" + (hours - 12);
} else if (hours == 0) {
timeValue= "12";
}
if(timeForDST != 0){
int num = Integer.parseInt(timeValue);
timeValue =String.valueOf(num + timeForDST);
}
timeValue += (minutes < 10) ? ":0" + minutes : ":" + minutes; // get minutes
timeValue += (hours >= 12) ? " PM" : " AM"; // get AM/PM
time = timeValue;
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(">>>>>>>>>> Final Time: " + time);
// save
}
});
}
Thank you in advance:)
You are working much too hard.
Never use the terrible legacy date-time classes such as SimpleDateFormat, TimeZone, Date, and Calendar classes. Use only the java.time classes.
I’m not clear on what format of text you receive. I’ll assume it is standard ISO 8601 format YYYY-MM-DDTHH:MM:SSZ. (If not, edit your Question for clarity.)
Instant instant = Instant.parse( "2022-01-23T12:34:56.123456789Z" ) ;
If desired, lop off unneeded detail.
instant = instant.truncatedTo( ChronoUnit.MINUTES ) ;
Adjust from an offset of zero hours-minutes-seconds from UTC to a particular time zone.
ZoneId z = ZoneId.of( "America/Edmonton" ) ; // Or ‘ZoneId.systemDefault()`.
ZonedDateTime zdt = instant.atZone( z ) ;
Extract the time of day.
LocalTime lt = zdt.toLocalTime() ;
Generate text in automatically localized format.
DateTimeFormatter f = DateTimeFormatter.ofLocalizedTime( FormatStyle.SHORT ).withLocale( Locale.CANADA_FRENCH ) ;
String output = lt.format( f ) ;
See this code run live at IdeOne.com.
These classes are built into Android 26+. For earlier Android, use the latest tooling with its “API desugaring” to access most of the java.time functionality.

how to execute a job at a certain time in a different timezone

Say if i am in BST i.e British Summer Time and i want to execute a job at 19.30 as per the US/Eastern timezone, then how could i acheive it.
Sample code that i tried,
Instant now = Instant.now();
LocalDateTime localTimeNow = LocalDateTime.ofInstant(now, ZoneOffset.systemDefault());
//if BST then use "Europe/London"
//if US/Eastern then use "America/New_York"
// For EST also use "America/New_York"
// If GB-Eire then use "Europe/London"
ZonedDateTime bsTime = now.atZone(ZoneId.of("Europe/London"));
ZonedDateTime nyAmerica = now.atZone(ZoneId.of("America/New_York"));
// Lets calculate the difference between 2 timezones
// Between London and EST
long timeDiff = ChronoUnit.MILLIS.between(bsTime, nyAmerica);
System.out.println("timeDiff - " + timeDiff);
int minutes = (int) ((timeDiff / 1000) / 60);
System.out.println("Time diff bet London and EST - " + minutes + " minutes");
long diff = Duration.between(bsTime, nyAmerica).getSeconds();
int mins = (int) (diff / 60);
System.out.println("Time diff bet London and EST - " + mins + " minutes");
It is giving me Zero in both cases.
What i want is that i have to use this delay to pass it to the executor service as below,
executor.schedule(myRunnable, delay, TimeUnit.SECONDS);
So even though i am in Britain, the job should get executed at at 19.30 as per the US/Eastern.
Also some of the abbreviations like EST, BST are not a valid ZoneId.
So how could i handle those cases when i have timezone in an abbreviated format like EST or BST etc. ?
UPDATE: Original answer below shows how to calculate local time to start a job that must run at a certain time of day in a different time zone.
If you just want to calculate how long to wait until that time, it can be done much easier, without involving the local time zone.
LocalTime jobStartTime = LocalTime.of(19, 30);
ZoneId jobZone = ZoneId.of("America/New_York");
ZonedDateTime now = ZonedDateTime.now(jobZone);
ZonedDateTime jobDateTime = now.with(jobStartTime);
if (jobDateTime.isBefore(now))
jobDateTime.plusDays(1);
long delay = ChronoUnit.MILLIS.between(now, jobDateTime);
System.out.println("now = " + now);
System.out.println("jobDateTime = " + jobDateTime);
System.out.println("delay = " + delay + " = " + Duration.ofMillis(delay));
Output
now = 2020-07-17T08:18:45.482028800-04:00[America/New_York]
jobDateTime = 2020-07-17T19:30-04:00[America/New_York]
delay = 40274517 = PT11H11M14.517S
Original Answer
now is 2020-07-17 07:57:45 Z
In London that is 2020-07-17 08:57:45 +01:00
In New York that is 2020-07-17 03:57:45 -04:00.
What is the time different between London and New York?
0 seconds, because they are the same time.
The code in the question doesn't calculate when the time will be 19:30. Instead, it attempts to calculates the time zone difference as of right now, but because of Daylight Savings Time, the time zone difference at 7:30 PM might be different, so the approach is wrong.
If you are in London, and need to know when it will next be 19:30 in New York, do it like this:
Instant now = Instant.now();
ZoneId localZone = ZoneId.of("Europe/London");
ZoneId remoteZone = ZoneId.of("America/New_York");
System.out.println("now = " + now);
ZonedDateTime remoteNow = now.atZone(remoteZone);
LocalDate remoteDate = remoteNow.toLocalDate();
LocalTime remoteTime = LocalTime.of(19, 30);
if (remoteNow.toLocalTime().isAfter(remoteTime))
remoteDate = remoteDate.plusDays(1);
ZonedDateTime remoteStartTime = ZonedDateTime.of(remoteDate, remoteTime, remoteZone);
System.out.println("remoteNow = " + remoteNow);
System.out.println("remoteStartTime = " + remoteStartTime);
ZonedDateTime localStartTime = remoteStartTime.withZoneSameInstant(localZone);
System.out.println("localNow = " + now.atZone(localZone));
System.out.println("localStartTime = " + localStartTime);
Output
now = 2020-07-17T07:57:45.206007800Z
remoteNow = 2020-07-17T03:57:45.206007800-04:00[America/New_York]
remoteStartTime = 2020-07-17T19:30-04:00[America/New_York]
localNow = 2020-07-17T08:57:45.206007800+01:00[Europe/London]
localStartTime = 2020-07-18T00:30+01:00[Europe/London]
So, on a computer running British time zone, the next 7:30 PM time in Eastern US is at half past midnight tonight.
You could try to use Spring Boot Quartz Scheduler
Reference: https://www.callicoder.com/spring-boot-quartz-scheduler-email-scheduling-example/

Java calculating time with timestamps [duplicate]

This question already has answers here:
Calculating the difference between two Java date instances
(45 answers)
Closed 7 years ago.
Im trying to calculate the time difference between 2 Timestamps, this is the code:
Calendar calendar = Calendar.getInstance();
java.util.Date now = calendar.getTime();
Timestamp currentTimestamp = new Timestamp(now.getTime());
System.out.println("Current\n"+currentTimestamp);
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = dateFormat.parse("28/02/2015");
Timestamp timestampBefore = new Timestamp(date.getTime());
System.out.println("Before\n"+timestampBefore);
Timestamp calculated = new Timestamp(currentTimestamp.getTime() - timestampBefore.getTime());
System.out.println("Calculated\n"+calculated);
Output:
Current
2015-02-28 12:12:40.975
Before
2015-02-28 00:00:00.0
Calculated
1970-01-01 13:12:40.975
I can understand why it returns 1970-01-01 but why does it return 13:12:40.975 ,1 hour more?
How to calculate the difference between 2 dates so the output is like this (based on this example):
Years:0, Months:0, Days:0, Hours:12, Minutes:12, Seconds:40 ?
Update: for java below 1.8 check out http://www.joda.org/joda-time/index.html
and for java 1.8 see answer.
Similar solution here: Java 8: Calculate difference between two LocalDateTime
(1) A timestamp is a point in time. If you calculate the difference between two timestamps, the result is not a timestamp (point in time), but a duration. So it is nonsense to convert the difference to a timestamp, hence it is useless to discuss the reason why the result is strange.
(2) You should probably use the new Java 8 time API (if you are able to use Java 8):
LocalTime now = LocalTime.now();
LocalTime previous = LocalTime.of(0, 0, 0, 0);
Duration duration = Duration.between(previous, now);
System.out.println(now);
System.out.println(previous);
System.out.println(duration);
Note that this just calculates the duration between two times of a day (hour-minute-second). If your want to include date information, use LocalDateTime instead:
LocalDateTime nextFirework = LocalDate.now()
.with(TemporalAdjusters.firstDayOfNextYear())
.atTime(LocalTime.MIDNIGHT);
LocalDateTime now = LocalDateTime.now();
// duration (in seconds and nanos)
Duration duration = Duration.between(now, nextFirework);
// duration in total hours
long hours = now.until(nextFirework, ChronoUnit.HOURS);
// equals to: duration.toHours();
If you want to have 'normalized' duration in years/months/days/hours/seconds, there is suprisingly no direct support. You could convert the duration to days, hours, minutes and seconds by yourself:
long d = duration.toDays();
long h = duration.toHours() - 24 * d;
long m = duration.toMinutes() - 60 * duration.toHours();
long s = duration.getSeconds() - 60 * duration.toMinutes();
System.out.println(d + "d " + h + "h " + m + "m " + s + "s ");
But note that you will have difficulties converting the days into months and years, as there is no unique number of days per month and a year can be a leap year with 366 days. For that, you can use Period, as in opposite to Duration, this class is associated with a timeline. Unfortunately, Period does only support dates, but no times:
// period in years/months/days (ignoring time information)
Period p = Period.between(now.toLocalDate(), nextFirework.toLocalDate());
System.out.println(p); // or use p.getYears(), p.getMonths(), p.getDays()
So probably you could combine both approaches - first, compute the Period from the dates and then the Duration using the times. Note that the duration can be negative, so you'll have to take care of that in case of:
Duration dur = Duration.between(start.toLocalTime(), end.toLocalTime());
LocalDate e = end.toLocalDate();
if (dur.isNegative()) {
dur = dur.plusDays(1);
e = e.minusDays(1);
}
Period per = Period.between(start.toLocalDate(), e);
System.out.println(per.toString() + ", " + dur.toString());

Check if time in millis is tomorrow

I want to query SQLite table and get records where the time field (which is a String representing long time in millis) is in the range of tomorrow from querying time.
I also have a field which holds the record date time like this:
dd/MM/yyyy, HH:mm:ss
How would you recommend implementing this?
As per your comment you are open to modify the schema for better performance. So it is better to save time as long (unix timestamp) in database and having an index on that. Once that is done you can simply get tomorrows date at 00:00 in local time zone and convert it to unix timestamp and query based on that. Here is how you can get tomorrows timestamp at 00:00,
public static long getTimeStampAt0000(long timestamp) {
Calendar givenDate = Calendar.getInstance();
givenDate.setTimeInMillis(timestamp);
givenDate.set(Calendar.HOUR_OF_DAY, 0);
givenDate.set(Calendar.MINUTE, 0);
givenDate.set(Calendar.SECOND, 0);
givenDate.set(Calendar.MILLISECOND, 0);
return givenDate.getTimeInMillis();
}
public static long getTimeStampAt0000ForTomorrow() {
long now = System.currentTimeMillis();
long nowAt0000 = getTimeStampAt0000(now);
if (now == nowAt0000) {
// if being queried at 00:00, we are assuming we want same or else we can just remove
// this condition
return nowAt0000;
} else {
return nowAt0000 + 86400000;
}
}
The SQLite doc says that it stores as:
INTEGER as Unix Time, the number of seconds since 1970-01-01 00:00:00 UTC.
Are you certain you have milliseconds since epoch or seconds?
The bundled java.util.Date and Calendar classes are notoriously troublesome. Avoid them. Use either Joda-Time or the new java.time.* package in Java 8.
Note that both java.util.Date and Joda-Time DateTime use milliseconds since epoch, while the new java.time uses nanoseconds. Multiply by 1000L as needed.
When talking about "today" and "tomorrow" with a date-time, you must specify a time zone. The beginning and ending of a day depends on time zone.
// Simulate input.
long millis = DateTime.now().getMillis();
// Use a proper time zone name rather than 3-letter codes.
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" ); // Formerly known as Calcutta, India.
DateTime dateTime = new DateTime( millis, timeZone );
DateTime aDayLater = dateTime.plusDays( 1 );
// "Tomorrow" is a span of time.
DateTime startOfToday = new DateTime( timeZone ).withTimeAtStartOfDay();
// Interval comparison is done in "half-open" approach where beginning is inclusive and ending is exclusive.
Interval tomorrow = new Interval( startOfToday.plusDays( 1 ), startOfToday.plusDays( 2 ) );
boolean isDateTimeOccurringTomorrow = tomorrow.contains( dateTime );
boolean isADayLaterOccurringTomorrow = tomorrow.contains( aDayLater );
Dump to console…
System.out.println( "millis: " + millis );
System.out.println( "dateTime: " + dateTime );
System.out.println( "aDayLater: " + aDayLater );
System.out.println( "startOfToday: " + startOfToday );
System.out.println( "tomorrow: " + tomorrow );
System.out.println( "isDateTimeOccurringTomorrow: " + isDateTimeOccurringTomorrow );
System.out.println( "isADayLaterOccurringTomorrow: " + isADayLaterOccurringTomorrow );
When run…
millis: 1392883763016
dateTime: 2014-02-20T13:39:23.016+05:30
aDayLater: 2014-02-21T13:39:23.016+05:30
startOfToday: 2014-02-20T00:00:00.000+05:30
tomorrow: 2014-02-21T00:00:00.000+05:30/2014-02-22T00:00:00.000+05:30
isDateTimeOccurringTomorrow: false
isADayLaterOccurringTomorrow: true

Create a Java Date from a String and vise versa

I have a date in Integer format(YYYYMMDD). And a start_time as a String (HH:mm 24 hour system). and a time_duration in hours as a double.
int date = 20140214;
String start_time = "14:30";
double duration = 50.30;
I want to use these 3 values and create 2 Java Date Objects. One is start_date and one is end_date. They should be in the format YYYY-MM-DD HH:mm.
And then after I get 2 data Strings like YYYY-MM-DD HH:mm. how can I obtain those previous variables. date, start_time, duration.
This is my attempt.
public void solve() throws IOException {
int date = 20140214;
String start_time = "14:30";
double duration = 24.50;
String startDate = "";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
startDate = getDate(date) + " " + start_time;
try {
Date start_Date = df.parse(startDate);
Date end_Date = new Date(start_Date.getTime()+(int)(duration*3600*1000));
System.out.println(df.format(start_Date));
System.out.println(df.format(end_Date));
} catch (ParseException ex) {
}
}
public String getDate(int dateInt) {
String date = "";
String dateIntString = String.valueOf(dateInt);
date = date + dateIntString.substring(0, 4) + "-";
date = date + dateIntString.substring(4, 6) + "-";
date = date + dateIntString.substring(6, 8);
return date;
}
Is there any easy way to do it. ? Or some built-in capabilities I can use other than those I have used ?
Strange Data Types For Date-Time
Using:
An int to represent the digits of a calendar date
A string to represent time-of-day digits
A double to represent a duration of fractional hours
…are all unusual approaches. Probably not the wisest choices in handling date-time values.
Avoid java.util.Date/Calendar
Know that the bundled classes java.util.Date and .Calendar are notoriously troublesome and should be avoided. Use either Joda-Time or the new java.time.* package (Tutorial) in Java 8. And get familiar with the handy ISO 8601 standard.
Time Zone
Your question and example ignore the crucial issue of time zone. Handling date-time data without time zone is like handling text files without knowing their character encoding. Not good.
Use proper time zone names to create time zone object. Avoid the non-standard 3-letter codes.
Joda-Time
In Joda-Time, a DateTime object is similar to a java.util.Date object but actually knows its own assigned time zone.
Joda-Time offers three classes for representing spans of time: Period, Duration, and Interval.
The Interval class uses the "Half-Open" approach, where the beginning is inclusive and the ending is exclusive. This approach works well for handling spans of time and comparisons. Look for the handy contains, abuts, overlap, and gap methods.
int dateInput = 20140214;
String start_timeInput = "14:30";
double durationInput = 50.30;
// Clean up these inputs.
String datePortion = Integer.toString( dateInput );
String input = datePortion + " " + start_timeInput;
DateTimeFormatter formatterInput = DateTimeFormat.forPattern( "yyyyMMdd HH:mm");
// Specify the time zone this date-time represents.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" ); // Or, DateTimeZone.UTC
DateTime dateTime = formatterInput.withZone( timeZone ).parseDateTime( input );
// Convert fractional hours to milliseconds, then milliseconds to a Duration object.
long millis = ( 60L * 60L * (long)(1000L * durationInput) ); // 1 hour = 60 minutes * 60 seconds * 1000 milliseconds.
Duration duration = new Duration( millis );
Interval interval = new Interval( dateTime, duration );
DateTimeFormatter formatterOutput = DateTimeFormat.forStyle( "MM" ).withLocale( Locale.FRANCE );
String description = "De " + formatterOutput.print( interval.getStart() ) + " à " + formatterOutput.print( interval.getEnd() );
Dump to console…
System.out.println( "input: " + input );
System.out.println( "dateTime: " + dateTime );
System.out.println( "duration: " + duration ); // Format: PnYnMnDTnHnMnS (from ISO 8601)
System.out.println( "interval: " + interval ); // Format: <start>/<end> (from ISO 8601)
System.out.println( "description: " + description );
When run…
input: 20140214 14:30
dateTime: 2014-02-14T14:30:00.000+01:00
duration: PT181080S
interval: 2014-02-14T14:30:00.000+01:00/2014-02-16T16:48:00.000+01:00
description: De 14 févr. 2014 14:30:00 à 16 févr. 2014 16:48:00
You have very many representations of date.
When in doubt, I usually head for getting to unix standard time (milliseconds since 1970) as soon as possible.
In this case it would be to convert the Integer date to a String, read out the four first as a year, two digits as month and the last two as day day, and then do the similar thing for the 24h time, and create a java.util.Date from this like so:
SimpleDateFormat dateParser=new SimpleDateFormat("yyyyMMdd HH:mm"); //please double check the syntax for this guy...
String yyyyMmDd = date.toString();
String fullDate = yyyyMmDd + " " + start_time;
java.util.Date startDate = dateParser.parse(fullDate);
long startTimeInMillis = startDate.getTime();
final long MILLISECONDS_PER_HOUR = 1000*60*60;
long durationInMillis = (long)duration*MILLISECONDS_PER_HOUR;
java.util.Date endDate = new java.util.Date(startTimeInMillis + durationInMillis);
Don't miss Joda time or Java 8 new, finally improved date handling named java.time.
you can write like
int date = 20140214;
String s=""+date;
Date date = new SimpleDateFormat("yyyyMMdd").parse(s);

Categories