I'm managing devices that report their system clock as seconds since midnight 01-01-1900.
I need to convert this into a timestamp.
So far, I'm doing this as follows:
import java.text.SimpleDateFormat;
import java.util.Calendar;
public class TestTime
{
// Pass seconds since 01-01-1900 00:00:00 on the command line
public static void main(String[] args)
{
// ---------------------
// Create time formatter
// ---------------------
SimpleDateFormat format;
format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// ---------------------------
// Compose 01-01-1900 00:00:00
// ---------------------------
Calendar cal;
cal = Calendar.getInstance();
cal.set(Calendar.YEAR, 1900);
cal.set(Calendar.MONTH, Calendar.JANUARY);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
// -------------------
// Show what we've got
// -------------------
System.out.println(format.format(cal.getTime()));
// ---------------------------------------------
// Add the seconds as passed on the command line
// ---------------------------------------------
long secs = Long.parseLong(args[0]);
while (secs > Integer.MAX_VALUE)
{
cal.add(Calendar.SECOND, Integer.MAX_VALUE);
secs -= Integer.MAX_VALUE;
}
cal.add(Calendar.SECOND, (int)secs);
// -------------------
// Show what we've got
// -------------------
System.out.println(args[0] + " corresponds to " + format.format(cal.getTime()));
} // main
} // class TestTime
When running this on my local PC (Italy, Windows 7), I get the following:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 10:13:20
This is perfectly correct.
I get the same results when running this on a Linux machine (still in Italy).
However, running the very same program on a Linux machine in Brazil, I get different results:
java -cp . TestTime 3752388800
1900-01-01 00:00:00
3752388800 corresponds to 2018-11-28 11:19:48
Whatever value I pass on the commandline, the difference is always 01:06:28.
Any idea where this difference is coming from?
BTW, I'm not concerned about the timezone. I just need a timestamp
Update 1:
The very same thing happens also when using Java 6 (which is the actual version used within our production environment in Brazil).
So, the problem does not depend on the java version
Update 2:
The problem does not occur when entering a number of seconds below 441763200 (which corresponds to 01-01-1914 00:00:00)
The question remains why we get a difference for Brazil?
java.time
A solution is to make sure you do your conversion in UTC:
Instant base = LocalDate.of(1900, Month.JANUARY, 1)
.atStartOfDay(ZoneOffset.UTC)
.toInstant();
String secsSince1900String = "3752388800";
long secsSince1900 = Long.parseLong(secsSince1900String);
Instant target = base.plusSeconds(secsSince1900);
System.out.println(target);
Output (independent of JVM time zone):
2018-11-28T10:13:20Z
The trailing Z in the output means UTC. I have tested while setting my JVM’s default time zone to America/Sao_Paulo, it made no difference. If you want, you can formate the date and time to your liking, for example:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String formattedDateTime = target.atOffset(ZoneOffset.UTC).format(formatter);
System.out.println(formattedDateTime);
2018-11-28 10:13:20
What went wrong when running in Brazil?
There are a number of time zones across Brazil. I took São Paulo as an example and reproduced your output readily. At the turn of the century in 1900, São Paulo was at offset -03:06:28 from GMT. Your Calendar uses the JVM’s default time zone, so you really set its time of day to 03:06:28 GMT, which explains the difference.
That said, the date-time classes you were using — SimpleDateFormat and Calendar — have design problems and have fortunately been replaced by java.time, the modern Java date and time API, with Java 8 nearly 5 years ago. One trait of the modern API is we more naturally make time zone explicit, which makes it easier to avoid issues like yours, and also to fix them if we run into them anyway.
Question: Our production Java version is Java 6. Can I use java.time?
Yes, java.time works nicely on Java 6. It has been backported.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Have a look at this site: https://www.timeanddate.com/time/zone/brazil/sao-paulo and navigate to Time zone changes for: 1900-1924. There you can see an offset of -03:06:28 to UTC before 01-01-1914. It is exactly the same reason as in Why is subtracting these two times (in 1927) giving a strange result?
On Jan 1st, 1914 Brazil changed the time and added 6 minutes and 28 seconds to their time moving from LMT to BRT (see Time Changes in São Paulo Over the Years, 1900-1924).
The additional one hour of difference is probably that Brazil spans 3 time zones (UTC-4, UTC-3, UTC-2) and you didn't set the time zone in your code, depending on the JVM system time zone.
Related
Could some one explain why this past date getting increased by one hour , when I convert it to Moscow Timezone ?
I'm using JDK 1.6.0_12 version. .
2011-04-02T11:39:46+0300 --> Sat Apr 02 12:39:46 MSK 2011 // 11:39 --> 12:39
My current system time-zone is "Europe/Moscow" UTC+3 .
Also please note that this past date is in DST(Daylight Saving ) time-zone period UTC+4 , earlier used in Russia.
There was a legislative change of Russian time-zone definitions in October 2014 . Since then Russia uses UTC+3 all through out a year .
I already checked
this old post of 2014 . But I think this issue looks different.
Our developers expect that every past date (like "2011-04-02T11:39:46+0300" and which is in DST period ), should contain current time zone offset value i.e +0300 , not +0400 . And they think JRE is converting it incorrectly to UTC+4 , though "Default Time Zone Offset" shows +3 here . Is this way of handling time-zone offset value for past dates correct?
Same output is given on JRE 1.8 , which I think is an updated version ,there shouldn't be any issue in TZ definition in JRE 1.8.
Thanks in Advance !
Java Code:
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;
public class HelloWorld{
public static void main(String []args)
{
String dateInString = "2011-04-02T11:39:46+0300";
System.out.println(dateInString);
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date = dateFormat.parse(dateInString);
System.out.println(date);
} catch (Exception e) {
System.out.println(e);
}
final TimeZone tzone = TimeZone.getDefault();
System.out.println("Default Time Zone ID - " + tzone.getID());
System.out.println("Default Time Zone Offset - (" + (tzone.getRawOffset() / 60 / 60 / 1000) + ") hour.");
}
}
Output :
2011-04-02T11:39:46+0300
Sat Apr 02 12:39:46 MSK 2011
Default Time Zone ID - Europe/Moscow
Default Time Zone Offset - (3) hour.
12:39 is the correct time
You are getting the correct result. In your string, 2011-04-02T11:39:46+0300, the trailing +0300 is an offset from UTC. So the point in time is the same as 2011-04-02T08:39:46+00:00 (UTC). As you say yourself, Moscow was at UTC offset +04:00 from 27 March 2011 to 26 October 2014. So to get the correct time for Moscow Java needs to add 1 hour to the hour in the string. Or 4 hours to the UTC hour of 08:39:46. In any case the time in Moscow was 12:39:46 at this point in time.
Or to answer your question:
… why this past date getting increased by one hour , when I convert it
to Moscow Timezone ?
Because Moscow on that date was 1 hour ahead of the time in the string.
java.time
That said I agree with those who recommend java.time, the modern Java date and time API, for the job. SimpleDateFormat is a notorious troublemaker of a class, and Date and TimeZone are poorly and confusingly designed too. All are long outdated. The modern API is so much nicer to work with.
For example:
ZoneId zone = ZoneId.of("Europe/Moscow");
ZonedDateTime zdt = ZonedDateTime.of(2011, 4, 2, 11, 39, 46, 0, zone);
System.out.println(zdt);
Output:
2011-04-02T11:39:46+04:00[Europe/Moscow]
You can also see from the output that Java knows that Moscow was at offset +04:00 back then.
Your question very well illustrates why java.time (opposite the old TimeZone class) makes the distinction between a time zone and an offset. A time zone includes all historic, the present and all known future offsets from UTC. This is what you need to represent historic times in Moscow correctly. In java.time a time zone is identified by a ZoneId object and obeys a ZoneRules object (most often we need not concern ourselves with the latter and can just trust Java to make the right conversions). A UTC offset is represented by a ZoneOffset object.
Question: how could I use java.time with Java 1.6?
This is your lucky day. java.time exactly requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On older Android either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Time Changes in Moscow Over the Years
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
Java 8+ APIs available through desugaring
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Both modern java date/time api and legacy one (that is used in jdk1.6) rely on system unix time and the tzdata file bundled with the JRE. Looks like the developers are right and your java is using a very old one version of tzdata and your developers are right.
Also, the tzdata keeps information about legal changes and if you are trying to convert date/time in the past, it will apply conversion rules that were relevant at that time.
Regarding JDK 1.8: there was an update to Russian timezone information in 8u101, so you should use at least 8u101 for a better timezone conversion.
The best decision for you would be to use modern java or update your JREs tzdata manually if you really need to use an old one.
You need to set time-zone to SimpleDateFormat as shown below:
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class Main {
public static void main(String[] args) throws ParseException {
String dateInString = "2011-04-02T11:39:46+0300";
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));// Set time-zone
Date date = dateFormat.parse(dateInString);
System.out.println(dateFormat.format(date));
}
}
Output:
2011-04-02T12:39:46+0400
Note that java.util.Date does not have time-zone information. It's simply the number of milliseconds from the standard Java epoch of 1970-01-01T00:00:00Z where Z stands for UTC (0 hour offset), also known as Zulu time-zone. At any given moment, you will get the same number of milliseconds on the JVMs sitting in any part of the word. When you try to print an object of java.util.Date, the date-time string for the JVM's time-zone is calculated from this milliseconds value and the same is displayed. If you want to get the date-time String in a specific time-zone, you need to set it explicitly to the SimpleDateFormat and use the same to format the java.util.Date.
When I print date that I get from server, it shows Mon Jun 24 16:15:31 GMT+09:00 2019
val formatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
val date: Date? = formatter.parse(checkedDate) // date from server
val transformedDate = ("${String.format("%02d", date!!.month + 1)}.${String.format("%02d", date!!.date)}.${date.year + 1900}")
val title: String? = ("$transformedDate")
val longGmtTime = date.time
val mZone = TimeZone.getDefault()
val offset = mZone.getOffset(longGmtTime)
val longLocalTime = longGmtTime + offset - (9 * HOUR)
val localDate = Date() // local date
localDate.time = longLocalTime
val localFormatTime = formatter.format(localDate)
val transformedLocalDate = ("${String.format("%02d", localDate!!.month + 1)}.${String.format("%02d", localDate!!.date)}.${localDate.year + 1900}")
And it gives me server time: 2019-06-24 16:15:31 -> 06.24.2019, local time(Asia/Seoul)-> 2019-06-25 01:15:30 ->06.25.2019 for the result.
The server time and local time must be the same. But the local time shows somewhere else.
What's the problem?
What's the problem?
The gross problem list includes:
You are using the poorly designed and long outdated Java date and time classes Date, TimeZone and SimpleDateFormat.
You are using the deprecated methods getMonth, getDate and getYear of the Date class. These methods work unreliably across time zone, which is the main reason why they were deprecated.
You are doing the time zone conversion manually using addition, subtraction and multiplication. Date and time math is error-prone, and you should always leave it to proven library methods.
The millisecond count you get from Date.getTime is since the epoch of 1970-01-01T00:00:00 UTC. This is a unique moment in time and independent of time zone, so adding to and subtracting from the millisecond count for time zone conversion makes no sense.
I can reproduce your result when I set my JVM’s default time zone to Asia/Seoul and assume that HOUR is 0 (or some value in the range from 0 through 111). I assume that you had wanted HOUR to denote the number of milliseconds in an hour, 3 600 000 (at least usually, exceptions exist).
You were formatting your date by concatenating the results of calls to Strirg.format. It’s better to leave formatting to a specialized date formatter.
The fix: java.time
ZoneId serverTimeZone = ZoneId.of("Asia/Seoul");
DateTimeFormatter serverFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
ZoneId clientTimeZone = ZoneId.systemDefault();
String checkedDate = "2019-06-24 16:15:31";
ZonedDateTime serverDateTime = LocalDateTime.parse(checkedDate, serverFormatter)
.atZone(serverTimeZone);
ZonedDateTime clientDateTime = serverDateTime.withZoneSameInstant(clientTimeZone);
System.out.println("clientDateTime: " + clientDateTime);
Sorry that I can write and run only Java code, I trust you to translate. With my JVM’s time zone still set to Asia/Seoul I get:
clientDateTime: 2019-06-24T16:15:31+09:00[Asia/Seoul]
The server time and the client time are the same, as you requested. If instead I keep my own time zone, I get:
clientDateTime: 2019-06-24T09:15:31+02:00[Europe/Copenhagen]
So there is a conversion taking place.
To format the date:
DateTimeFormatter displayFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)
.withLocale(Locale.forLanguageTag("ko-KR"));
String transformedLocalDate = clientDateTime.format(displayFormatter);
System.out.println("transformedLocalDate: " + transformedLocalDate);
transformedLocalDate: 2019. 6. 24.
Or if you insist on month.date.year:
DateTimeFormatter displayFormatter = DateTimeFormatter.ofPattern("MM.dd.u");
transformedLocalDate: 06.24.2019
A further recommendation would be to have your server deliver a date-time string in UTC in ISO 8601 format. That would go like 2019-06-24T07:15:31Z for the moment used in the examples.
Question: Can I use java.time with minSdk API level 23 on Android?
Yes, java.time works nicely on older and newer Android devices. It just requires at least Java 6.
In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.
Links
Oracle tutorial: Date Time explaining how to use java.time.
Java Specification Request (JSR) 310, where java.time was first described.
ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Wikipedia article: ISO 8601
You should specify setup server timezone instead of you device (which is default)
sorry if the title is confusing. Let me explain clearly. I need to play with days, months and years. In order to do this I use Calendar. Here is my code;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
int dayStart=0,monthStart=0,yearStart=0,dayFinish=0,monthFinish=0,yearFinish=0;
Calendar cal = (Calendar) Calendar.getInstance();
cal.set(Calendar.MONTH,Calendar.MAY); //SET MONTH AS MAY
cal.set(Calendar.DATE,1);
cal.set(Calendar.YEAR,2018);
monthStart=(cal.getCalendar.MONTH)+1);
dayStart=cal.get(Calendar.DATE);
yearStart=cal.get(Calendar.YEAR);
System.out.println("STARTING DAY: "+dayStart+" STARTING MONTH: "+monthStart+" STARTING YEAR: "+yearStart);
cal.add(Calendar.MONTH,6); //ADD 6 MONTHS
monthFinish = (cal.get(Calendar.MONTH)+1);
dayFinish = (cal.get(Calendar.DATE));
yearFinish = (cal.get(Calendar.YEAR));
System.out.println("FINISHING DAY: "+dayFinish+" FINISHNG MONTH: "+monthFinish+" FINISHING YEAR: "+yearFinish);
//WHAT I WANT IS printing out the days between 2 dates: 184
}
First, I set the time: 1 5 2018, then I add 6 months and the time becomes 1 11 2018. I need to get day difference as 184 (If I set the month January, it should be 181) Is it possible to do it just converting the corresponding Calendar fields (date,month,year) to secs or milliseconds and subtract millisecond value of (1 5 2018) from the (1 11 2018) and convert back milliseconds to days? There are similar questions but I couldn't find the solution exactly in the way I want.
java.time
LocalDate start = LocalDate.of(2018, Month.MAY, 1);
LocalDate finish = start.plusMonths(6);
long daysBetween = ChronoUnit.DAYS.between(start, finish);
System.out.format("Days between %s and %s: %d%n", start, finish, daysBetween);
IMHO it’s clear and it’s brief. And the bonus, it works correctly. Output is:
Days between 2018-05-01 and 2018-11-01: 184
The Calendar class has design problems and is now long outdated. So I recommend using java.time, the modern Java date and time API, instead. There is a way to have a Calendar count days correctly, but it’s more complicated than you would expect, and there is no reason why you should want to bother. Calculating the days from the milliseconds (which is shown in several answers on Stack Overflow, not only the other answer to this question) will sometime give the correct result, sometimes not. The two issues are: (1) Due to summer time (DST) and other discontinuities a day may be 23, 24 or 25 hours or some number between or even outside this interval. If a day in the interval is shorter than 24 hours, converting from the milliseconds will yield 1 day too little. (2) A Calendar (despite its name) also holds time of day. In your code it will hold the same time of day before and after you add 6 months. In other cases the different time of day may cause you to get 1 day too few, or in rare cases 1 day too many.
Question: Can I use java.time on Android?
Yes, java.time works nicely on Android devices. It just requires at least Java 6.
In Java 8 and later and on new Android devices (from API level 26, I’m told) the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310, where the modern API was first described).
On (older) Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. Make sure you import the date and time classes from package org.threeten.bp and subpackages.
Links
Oracle tutorial: Date Time, explaining how to use java.time.
ThreeTen Backport project
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Java Specification Request (JSR) 310.
You can try the something similar to this should work for you
import java.util.*;
import java.util.concurrent.TimeUnit;
public class Calendar1 {
public static void main(String args[])
{
Calendar startDate = Calendar.getInstance();
//Setting year, month and day
startDate.set(2018, 5, 1);
Calendar endDate = Calendar.getInstance();
endDate.set(2018, 11, 1);
long end = endDate.getTimeInMillis();
long start = startDate.getTimeInMillis();
System.out.println("Time difference in days " + TimeUnit.MILLISECONDS.toDays(Math.abs(end - start)));
}
}
Something this you can do. Change the year, Month and Date and set in the calendar.
Use java.time.temporal.ChronoUnit to get the difference.
The sample code is as below.
public void daysBetween() {
Calendar startOfMonth = Calendar.getInstance();
startOfMonth.set(Calendar.YEAR, 2018);
startOfMonth.set(Calendar.MONTH, 10);
startOfMonth.set(Calendar.DAY_OF_MONTH, 1);
Calendar endOfMonth = Calendar.getInstance();
endOfMonth.set(Calendar.YEAR, 2018);
endOfMonth.set(Calendar.MONTH, 10);
endOfMonth.set(Calendar.DAY_OF_MONTH, 30);
System.out.println(ChronoUnit.DAYS.between(startOfMonth.toInstant(),endOfMonth.toInstant()));
}
I am setting a Calendar day of month with an int value but when I check the value again the day of month from the created calendar it is 1 more than I set it to. And I am not sure why?
Here is an example:
System.out.println("DEBUG: Reminder day of month = " + reminder.getReminderDayofMonth());
calendar.set(Calendar.YEAR, reminder.getReminderYear());
calendar.set(Calendar.MONTH, reminder.getReminderMonth());
calendar.set(Calendar.DAY_OF_MONTH, reminder.getReminderDayofMonth());
calendar.set(Calendar.HOUR, reminder.getReminderHour());
calendar.set(Calendar.MINUTE, reminder.getReminderMinute());
System.out.println("DEBUG: Calendar day of month = " + calendar.get(Calendar.DAY_OF_MONTH));
I did the println so you can see the value in and the value out. I would expect that calling calander.get(Calander.DAY_OF_MONTH) would return the same value as I put into it. But it doesn't, I get:
DEBUG: Reminder day of month = 18
DEBUG: Calendar day of month = 19
I am sure it is probably something simple but I have no idea why they would be different and I can't find anything in the docs to explain the discrepancy
What is the problem?
Thanks for your help
TL:DR
LocalDateTime ldt = LocalDateTime.of(
reminder.getReminderYear(),
reminder.getReminderMonth() + 1, // Add one to adjust from zero-based counting.
reminder.getReminderDayofMonth(),
reminder.getReminderHour(),
reminder.getReminderMinute()
);
java.time
I suggest you put an end to using the very old and long outmoded Calendar class. Today we have so much better in java.time, the modern Java date and time API also known as JSR-310. The above code gives you the equivalent of what I think you were trying. I assumed getReminderMonth() returned 0-based month, so added 1 since the modern API numbers months from 1 just as humans do. If you can, I recommend you use an OffsetDateTime or ZonedDateTime to make the point on the time line unambiguous.
Question: Can I use the modern API with my Java version?
If using at least Java 6, you can.
In Java 8 and later the new API comes built-in.
In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR-310; link below).
On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. See the linked question below.
What went wrong in your code
I think the observed date increment happens when both of the following conditions are met:
Your code is running in the afternoon, that is at 12 noon or later in the Calendar’s time zone (typically the JVM’s time zone, in turn typically your local time zone).
getReminderHour() returns an hour in the afternoon, that is, 12 or later.
I cannot be 100 % sure since you haven’t shown us the code that produced your bug. But very likely your Calendar instance was created with the current time (Calendar.getInstance() and new GregorianCalendar(), for example, do this). In the afternoon it is obviously created with a time in PM. Then when you call calendar.set(Calendar.HOUR, reminder.getReminderHour()), this tries to set the hour within PM, but since the hour is 12 or greater, this overflows into AM of the following day. An hour of 14 (PM), for example, becomes 2 AM the next day.
If I am correct, the problem may seem solved not because you moved the creation of the calendar object inside your if statement, but because either you ran your program in the morning or the reminder hour was in the morning (before 12 noon). And your bug may surface again next time both the above-mentioned conditions apply,
Links
Oracle tutorial trail: Date Time
Question: How to use ThreeTenABP in Android Project
ThreeTen Backport home page
Java Specification Request (JSR) 310, where the modern API was first defined
I am getting a little crazy with date and time libraries in Java. Basically what I need is to get two String dates, the first one corresponds to the previous day in Australia time (taking into account daylight time) with a specific hour (will come as a parameter) and with the following date format: "yyyy-MM-dd'T'HH:mm:ss.SSS zzz".
Consider I will receive the time as a string like the following: "180000". So if today is Nov-17 in Australia, I will need to get the following String:
"2017-11-16T18:00:00.000 AEDT"
And the second string date I need is the same day as today in au time:
"2017-11-17T18:00:00.000 AEDT"
I am not able to use JDK 8, I must use JDK 7.
I tried different ways but I am not getting what I need. Any suggestion will be great.
I saw your comment that you cannot use Java 8, you must use JDK 7. At the same time, especially for not quite trivial run-of-the-mill operations like yours, java.time, the modern Java date and time API that came out with Java 8 in 2014 is so much nicer to work with. Fortunately the modern API has been backported to Java 6 and 7 too, in the ThreeTen Backport (that’s ThreeTen for JSR-310, where the API was first described). So I encourage you to get the backport and start coding:
ZoneId australianTime = ZoneId.of("Australia/Sydney");
DateTimeFormatter receivedTimeFormat = DateTimeFormatter.ofPattern("HHmmss");
DateTimeFormatter neededDateTimeFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS zzz",
Locale.forLanguageTag("en-AU"));
LocalDate today = LocalDate.now(australianTime);
LocalDate yesterday = today.minusDays(1);
String receivedTimeString = "180000";
LocalTime time = LocalTime.parse(receivedTimeString, receivedTimeFormat);
String previousDayAtTime = yesterday.atTime(time)
.atZone(australianTime)
.format(neededDateTimeFormatter);
System.out.println(previousDayAtTime);
When I ran this snippet today, it printed the requested output for yesterday:
2017-11-16T18:00:00.000 AEDT
I trust you to do similarly for today.
Since you had AEDT in your requested result, I picked Australia/Sydney as time zone over Australia/Darwin or other Australian options.
Using the backport is also the futureproof solution: you will need the backport only until one day you upgrade to Java 8 or later (Java 9 is out already). When upgrading, simply change your import statement from org.threeten.bp to java.time.