When the string "2017-04-21T17:46:00Z" is passed into the first method the resulting formatted date string is "06:46 21 Apr 2017". Why is the hour moving by eleven hours? The input strings are being provided by an HTTP server application in JSON. I thought the Z suffix referred to Zulu, ie GMT.
private static final String DATE_TIME_FORMAT = "hh:mm dd MMM yyyy";
public static String formatTimestamp(String dateTimestamp) {
DateTime dateTime = getDateTimeFromTimestamp(dateTimestamp);
DateTimeFormatter fmt = DateTimeFormat.forPattern(DATE_TIME_FORMAT);
return fmt.print(dateTime);
}
private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
return new DateTime(dateTimestamp);
}
I suspect it relates to timezones but it's not clear how or where. The code is running on an Android device in the UK, in the GMT timezone.
I've made a test with java 7 and joda-time 2.7 (but not the Android's version)
That's how I could reproduce the problem:
// changing my default timezone (because I'm not in UK)
DateTimeZone.setDefault(DateTimeZone.forID("Europe/London"));
// calling your method
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
The output is
06:46 21 Abr 2017
To check what's wrong, I've changed the date format to:
DATE_TIME_FORMAT2 = "hh:mm a dd MMM yyyy Z z zzzz";
Where a means "AM or PM", Z is the timezone offset/id, z is the timezone "short" name and zzzz is the timezone "long" name. Using this format, the output is:
06:46 PM 21 Abr 2017 +0100 BST British Summer Time
So the datetime created is 6PM, just one hour ahead of input, not eleven hours as you thought (actually if you change the format to HH instead of hh, the hours will be 18 instead of 06).
Also note the timezone fields: +0100 BST British Summer Time. The first part (+0100) means that this DateTime is one hour ahead of GMT, and BST British Summer Time means it's in British's Daylight Saving Time.
So, to have your output equals to your input, you have 2 alternatives:
1. Change your default timezone to UTC:
DateTimeZone.setDefault(DateTimeZone.UTC);
System.out.println(formatTimestamp("2017-04-21T17:46:00Z"));
The output will be:
05:46 21 Apr 2017
If you want to change the hours to be 17:46, change your date format, replacing hh by HH
2. Use the DateTime constructor that receives a DateTimeZone:
private static DateTime getDateTimeFromTimestamp(String dateTimestamp) {
// creates a DateTime in UTC
return new DateTime(dateTimestamp, DateTimeZone.UTC);
}
The output will be the same as alternative 1, but in this case you don't need to change the default timezone.
For me, alternative 2 makes more sense, because:
you don't need to change the default timezone (which can cause some mess in other parts of the application)
you already know that all dates handled by this code are in UTC time (because of the "Z" in the end)
Using java.time
The Answer by Hugo seems to be correct and informative. But FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. For Android, see the last bullet at bottom below.
Your input string is in standard ISO 8601 format. The java.time classes use standard formats when parsing & generating strings. So no need to specify a formatting pattern.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
String input = "2017-04-21T17:46:00Z" ;
Instant instant = Instant.parse( input ) ;
instant.toString(): 2017-04-21T17:46:00Z
For more flexible formatting such as you desire, convert to an OffsetDateTime object were you can specify any offset-from-UTC in hours and minutes. We want UTC itself (an offset of zero) so we can use the constant ZoneOffset.UTC.
OffsetDateTime odt = instant.atOffset( ZoneOffset.UTC ) ;
odt.toString(): 2017-04-21T17:46Z
Define a formatting pattern to match your desired format. Note that you must specify a Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm dd MMM yyyy" , Locale.US ) ;
String output = odt.format( f ) ;
output: 05:46 21 Apr 2017
If you want to see this same moment through the lens of a region’s wall-clock time such as Europe/London or Pacific/Auckland, apply a time zone to get a ZonedDateTime.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST or BST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Europe/London" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Note the time-of-day is an hour off because of Daylight Saving Time (DST).
zdt.toString(): 2017-04-21T18:46+01:00[Europe/London]
See this code run live at IdeOne.com.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
Related
val startHour = SimpleDateFormat("HH:mm").format(pickup.begin())
The pickup.begin value is "Wed Apr 10 10:00:00 GMT+03:00 2019", so I need the start hour to be 10:00 +3h -> 13:00, but I get startHour value of 10:00.
I don't know how to add the GMT value to hour.
No, you’ve misunderstood. Wed Apr 10 10:00:00 GMT+03:00 2019 is (the textual representation of) a java.util.Date the value of which equals 2019-04-10T07:00 UTC. It seems your default time zone is GMT+03:00, and Date is trying to be friendly to you and print the time in this time zone, which is why it prints 10:00:00. 13:00 would certainly be incorrect no matter if you wanted the time in UTC or in your own default time zone.
The Date class returned from pickup.begin() is poorly designed and long outdated, so you may want to consider if a type from java.time, the modern Java date and time API, could be returned instead. It may also make the matter clearer.
Alternatively, convert that java.util.Date object to its modern counterpart, a java.time.Instant. Look for new conversion methods added to the old classes.
Instant instant = pickup.begin().toInstant() ; // Converting legacy `Date` object to modern `Instant` object.
Search Stack Overflow and read the Oracle Tutorial to learn more about Instant, OffsetDateTime, and ZonedDateTime classes.
You can use java.time on older Android versions if you add ThreeTenABP to your Android project. It’s the Android adaptation of the backport of java.time.
Links
ThreeTenABP, Android edition of ThreeTen Backport
Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
Try adding a Locale to your simpledateformat, matching the +3 timezone.
val startHour = SimpleDateFormat("HH:mm", Locale.Germany).format(pickup.begin())
You can try something like this
I take 'date' as string here
String date="something"
val sdf = SimpleDateFormat("HH:mm")
sdf.timeZone = TimeZone.getTimeZone("UTC")
val gmt = sdf.parse(date)
If this is your case
Date date="somevalue"
then
val gmt = sdf.format(date)
gmt will return you your local time
I have the following String that I would like to change to UTC:
Thu Aug 24 07:38:32 GMT+01:00 2017
I'm using Joda-Time library.
I know how to create a new Datetime eg new dateTime(DateTimeZone.UTC) but how can I create a DateTime object from the above String?
I have tried the following but get an exception. Surely there must be another way to create a DT obect without chopping the original String up? What if the external API changes how it sends my app the orignal String, my String manipulation code would fail.
DateTimeFormatter df = DateTimeFormat.forPattern("dd-MMM-YYYY HH:mm");
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
Log.e(TAG, "dt after parse = " + dt.toString());
Error:
Caused by: java.lang.IllegalArgumentException: Invalid format: "Thu Aug 24 07:38:32 GMT+01:00 2017"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:866)
at org.joda.time.DateTime.parse(DateTime.java:144)
The format used (dd-MMM-YYYY HH:mm) means: day (dd) followed by -, followed by month (MMM), followed by -, followed by year (YYYY) and so on (check the javadoc for more details).
This format doesn't match the input string (which has day-of-week followed by month, followed by day, then hour/minute/second, etc). So the first thing is to use a format that matches the input, otherwise you'll always get "Invalid format" errors.
Another detail is that day of week and month names are in English, so you must also use a java.util.Locale to specify the language you're using to parse the input. If you don´t use a locale, the system default will be used, and it's not guaranteed to always be English (and it can also be changed, even at runtime, so it's always better to specify one).
I also had to add "GMT" as a literal and call withOffsetParsed() to make it include the offset (+01:00) in the parsed object:
DateTimeFormatter df = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
System.out.println(dt.toString());
The output is:
2017-08-24T07:38:32.000+01:00
Then, you can set the UTC timezone to this object:
dt = dt.withZone(DateTimeZone.UTC);
System.out.println(dt.toString());
The output will be:
2017-08-24T06:38:32.000Z
Note that withZone method preserves the same instant (both dates represent the same point in time), just the timezone used in the output is changed. But both dates are equivalent (they represent the same instant, as 07:38 in offset +01:00 is the same as 06:38 in UTC).
If you want all dates to be converted to UTC, you can also set this in the formatter:
// set UTC to the formatter
df = df.withZone(DateTimeZone.UTC);
Then you don't need to call withZone in the DateTime objects: all parsed dates will be converted to UTC.
You also told that "if the external API changes how it sends my app the orignal String, my String manipulation code would fail".
Well, if the input String changes, you'll have to change your format as well - there's no other way, Joda-Time can't just guess what's the format, you have to tell it.
If you want to parse more than one format, there's a way to create a formatter that uses lots of different patterns and try to parse each one, until one of them works (or throw exception if none works). You could do something like that:
// format 1
DateTimeFormatter f1 = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
// format 2
DateTimeFormatter f2 = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss Z");
// array of all possible formats
DateTimeParser[] parsers = { f1.getParser(), f2.getParser() };
// formatter that uses all the possible formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// append array of possible formats
.append(null, parsers)
// create formatter
.toFormatter().withLocale(Locale.ENGLISH).withOffsetParsed()
// set all parsed objects to UTC
.withZone(DateTimeZone.UTC);
// parse first format
System.out.println(DateTime.parse("Thu Aug 24 07:38:32 GMT+01:00 2017", formatter));
// parse second format
System.out.println(DateTime.parse("24/08/2017 07:38:32 +01:00", formatter));
Both dates will be parsed to:
2017-08-24T06:38:32.000Z
Then you can add new formats to the array, as needed.
Java new Date/Time API
Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
The code to parse the inputs is very similar, with minor changes in the format.
And I'm using the Instant class, because you want the output in UTC, and Instant represents a UTC instant:
// format 1
DateTimeFormatter f1 = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O yyyy", Locale.ENGLISH);
// format 2
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss XXX");
// formatter with both formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// add format 1
.appendOptional(f1)
// add format 2
.appendOptional(f2)
// create formatter
.toFormatter(Locale.ENGLISH);
// parse first format
System.out.println(Instant.from(formatter.parse("Thu Aug 24 07:38:32 GMT+01:00 2017")));
// parse second format
System.out.println(Instant.from(formatter.parse("24/08/2017 07:38:32 +01:00")));
This will output:
2017-08-24T06:38:32Z
2017-08-24T06:38:32Z
String DOB = new DateTime(Long.parseLong(dob) * 1000, DateTimeZone.UTC ).toString();
// Current
// YYYY-MM-DD
// DOB = "1994-05-10T00:00.000Z"
// Required
// DD-MM-YYYY
// DOB = "10-05-1994"
I want to remove the hh:mm:ss and format the date using Joda-Time DateTimeFormatter.
try this:
DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS zzz");
// pass your DOB String
DateTime jodatime = dtf.parseDateTime(DOB);
// Format for output
DateTimeFormatter dtfOut = DateTimeFormat.forPattern("dd-MM-yyyy");
// Print the date
System.out.println(dtfOut.print(jodatime));
tl;dr
Use java.time classes.
Instant.ofEpochSecond( 1_485_748_890L )
.atZone( ZoneId.of( "America/Montreal" ) )
.toLocalDate()
.format(
DateTimeFormatter.ofPattern ( "dd-MM-uuuu" )
.withLocale ( Locale.UK )
)
29-01-2017
Joda-Time
If you want a date-only value without a time-of-day, you should be using the org.joda.time.LocalDate class.
FYI, the Joda-Time project is now in maintenance mode, with the team advising migration to the java.time classes. Much of java.time is back-ported to Java 6, Java 7, and Android (see below).
java.time
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate birthdate = LocalDate.of( 1994 , 5 , 10 );
If your input is a count of whole seconds since the epoch of first moment of 1970 in UTC (1970-01-01T00:00:00Z), convert to an Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.ofEpochSecond( 1_485_748_890L );
To view this moment through the lens of a particular region’s wall-clock time, assign a time zone (ZoneId) to get a ZonedDateTime.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( z );
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate ld = zdt.toLocalDate();
To generate a String representing the value of your object, call toString for a string in standard ISO 8601 format, YYYY-MM-DD.
ld.toString(): 2017-01-29
For other formats, use the DateTimeFormatter class. You can specify a formatting pattern, or let the class automatically localize.
DateTimeFormatter f = DateTimeFormatter.ofPattern ( "dd-MM-uuuu" ).withLocale ( Locale.UK );
String output = ld.format ( f );
instant.toString(): 2017-01-30T04:01:30Z
zdt.toString(): 2017-01-29T23:01:30-05:00[America/Montreal]
ld.toString(): 2017-01-29
output: 29-01-2017
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
try this :
String textDate ="1994-05-10T00:00.000Z"; //Date to convert
DateTimeFormatter DATE_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ssZ"); //Default format
SimpleDateFormat SIMPLE_DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy", Locale.getDefault()); //Needed format
DateTime dateTime = new DateTime(DATE_FORMAT.parseDateTime(textDate), DateTimeZone.forID(current.getID()));
Calendar cal=dateTime.toCalendar(Locale.getDefault());
String formatted = SIMPLE_DATE_FORMAT.format(cal.getTime()); //Final Required date
In my app, I receive dates from a webservice in the form yyyy-MM-dd (e.g. 2016-03-05) and I need to format them as [abbreviated month] [date], e.g. Mar 5. Additionally, I have a start and end date and want to show them as a date range, unless both dates are the same.
Currently I'm using DateUtils.formatDateRange(), which should take care of my requirements and provide proper localization, but I'm running into two problems:
When my end date is the day after my start date, formatDateRange()
only shows the formatted start date. For example, if start date is
2016-03-05 and end date is 2016-03-06, the method returns Mar 5 (but it should be Mar 5 - Mar 6). Why does this happen?
When the end date is in the same month, the month is not shown. For example, if start date is 2016-03-05 and end date is
2016-03-12, the method returns Mar 5 - 12. Is there a way to make it show Mar 5 - Mar 12 instead?
Here is my code:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date startDate, endDate;
try {
startDate = sdf.parse(startDateString);
endDate = sdf.parse(endDateString);
} catch (ParseException ignored) {
return null;
}
int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH;
return DateUtils.formatDateRange(context, startDate.getTime(), endDate.getTime(), flags);
In the first case, the date formatter is taking your end date in the range as exclusive (as opposed to inclusive in the range). If you simply add one millisecond to the end date, you will see the ranges you expect, because now the date range includes the point in time at midnight for the end date.
In the second case, I'm afraid you are up to the current locale rules for date formatting. You pretty much have to accept what Android thinks is the best formatting, or come up with your own rules for each locale that you want to support.
tl;dr
LocalDate.parse( inputStart )
.format( DateTimeFormatter.ofPattern( "MMM d" ).withLocale( Locale.US ) )
+ " - " +
LocalDate.parse( inputStop )
.format( DateTimeFormatter.ofPattern( "MMM d" ).withLocale( Locale.US ) )
Mar 5 - Mar 6
Details
You can do this quite simply with the java.time classes rather than the troublesome old legacy date-time classes ( Date, SimpleDateFormat ) and the external library DateUtils.
Your input date strings use the standard ISO 8601 format. The java.time classes use the standard formats by default when parsing/generating strings. So no need to specify a formatting pattern.
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate start = LocalDate.parse( "2017-01-23" );
LocalDate stop = LocalDate.parse( "2017-02-14" );
To generate a string with just the abbreviated month name and day-of-month, use DateTimeFormatter.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "MMM d" );
Specify a Locale to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, separators, and such.
f = f.withLocale( Locale.US ) ; // Or Locale.CANADA_FRENCH, Locale.UK, Locale.ITALY, etc.
Ask the LocalDate to generate a string representing its value.
String output = start.format( f ) + " - " + stop.format( f ) ;
Jan 23 - Feb 14
MonthDay
Sounds like you may be interested in the MonthDay class if needing to work with the concept of a month and a day-of-month but without any year.
MonthDay md = MonthDay.of( 1 , 23 ) ;
Or use the Month enum to specify the month argument.
MonthDay start = MonthDay.of( Month.JANUARY , 23 ) ;
MonthDay stop = MonthDay.of( Month.FEBRUARY , 14 ) ;
To generate a string in standard ISO 8601 format, call toString.
String output = start.toString() ;
--01-23
Or use the same DateTimeFormatter seen above.
String output = start.format( f );
Jan 23
The ISO 8601 defines a format indicating a span of time using a slash character. So your same range of month-day values would be:
String output = start.toString() + "/" + stop.toString() ;
--01-23/--02-14
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
I want to convert milliSeconds in long format to Gregorian Calendar.
By searching in the web, i use the code below:
public static String getStringDate(int julianDate){
GregorianCalendar gCal = new GregorianCalendar();
Time gTime = new Time();
gTime.setJulianDay(julianDate);
gCal.setTimeInMillis(gTime.toMillis(false));
String gString = Utils.getdf().format(gCal.getTime());
return gString;
}
public static SimpleDateFormat getdf(){
return new SimpleDateFormat("yyyy-MM-dd, HH:MM",Locale.US);
}
Yes, the code works but i find that only the date and the hour are correct but there are errors on minutes. Say if the thing happens on 2014-11-06, 14:00, it will give me 2014-11-06, 14:11. I want to know are there any solutions to modify it or it is not recommended to convert time into Gregorian Calendar. Many thanks!
The problem actually is very simple,
modify SimpleDateFormat("yyyy-MM-dd, HH:MM",Locale.US) with
SimpleDateFormat("yyyy-MM-dd, HH:mm",Locale.getDefault());
will solve the problem
tl;dr
Instant.ofEpochMilli( millis ) // Convert count-from-epoch into a `Instant` object for a moment in UTC.
.atZone( ZoneId.of( "Pacific/Auckland" ) ) // Adjust from UTC to a particular time zone. Same moment, different wall-clock time. Renders a `ZonedDateTime` object.
.format( // Generate a String in a particular format to represent the value of our `ZonedDateTime` object.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd, HH:mm" )
)
java.time
The modern approach uses the java.time classes instead of those troublesome legacy classes.
Convert your count of milliseconds since the epoch reference of first moment of 1970 (1970-01-01T00:00Z) to a Instant object. Be aware that Instant is capable of finer granularity of nanoseconds.
Instant instant = Instant.ofEpochMilli( millis ) ;
That moment is in UTC. To adjust into another time zone, apply a ZoneId to get a ZonedDateTime.
A time zone is crucial in determining a date. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
If no time zone is specified, the JVM implicitly applies its current default time zone. That default may change at any moment, so your results may vary. Better to specify your desired/expected time zone explicitly as an argument.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
Generate a string in your desired format using a DateTimeFormatter object.
DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuu-MM-dd, HH:mm" , Locale.US ) ;
String output = zdt.format( f ) ;
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….