Home > Net >  Which is the correct way to use Java's date formats in Android Studio?
Which is the correct way to use Java's date formats in Android Studio?

Time:11-19

I am trying to build a chat app and I want to store date for every message in Firebase RealTime-Database using ServerValue.TIMESTAMP which stores date and time in milliseconds and it is server sided. All I want to achieve is to convert milliseconds to a safe date format which will have a pattern like "Thursday, 11th November 2022, 14:42" but I read a lot of things about Java's unsafe date and format libraries. My app uses FirebaseUI which is like an asynchronous way to observe/notify/listen to changes of my db so I need something that will be safe and supported from API/SDK level 21

Here is my code that I currently have

Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(model.sentOnDateInMilliseconds); String date = DateFormat.getDateInstance(DateFormat.FULL).format(calendar.getTime());

and I make attempts to preview the format that I want like this

textView.setText(MessageFormat.format("{0} {1}:{2} {3}", date, calendar.get(Calendar.HOUR), calendar.get(Calendar.MINUTE), calendar.get(Calendar.AM_PM)));

any suggestions?

CodePudding user response:

Avoid legacy classes

Never use SimpleDateFormat, Calendar, or either Date class. These legacy classes are terribly flawed with poor design decisions by people who did not understand date-time handling.

Their modern replacements are the java.time classes defined in JSR 310.

java.time

You are using terrible date-time classes that were years ago supplanted by the modern java.time classes defined in JSR 310.

Though not documented clearly, apparently a firebase.database.ServerValue.TIMESTAMP type represents a moment as a count of milliseconds since the epoch reference of the first moment of 1970 in UTC, 1970-01-01T00:00:00Z.

java.time.Instant

The matching class in Java is java.time.Instant.

Instant instant = Instant.ofEpochMilli( millisSinceEpoch ) ;

You can extract that millisecond count from an Instant. Beware of data loss: A Instant has a resolution of nanoseconds, so getting a count of milliseconds ignores the microseconds/nanoseconds.

Instant instant = Instant.now() ;  // Capture the current moment as seen with an offset of zero hours-minutes-seconds from UTC.
long millisSinceEpoch = instant.toEpochMilli() ;

java.time.ZonedDateTime

convert milliseconds to a safe date format which will have a pattern like "Thursday, 11th November 2022, 14:42"

To generate text in formats other than standard ISO 8601, we need a class more flexible than Instant. And we need to adjust that moment from an offset of zero hours-minutes-seconds from UTC to a time zone (or offset) expected by the user.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

java.time.format.DateTimeFormatter

To generate text, we must specify a format. You can hard-code a format, or you can let java.time automatically localize. To localize, we specify a Locale to determine the human language and cultural norms needed for localization such as name of day of week.

Locale locale = Locale.UK ;
DateTimeFormatter f = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( f ) ;

Dump to console.

System.out.println( "instant = "   instant );
System.out.println( "millisSinceEpoch = "   millisSinceEpoch );
System.out.println( "output = "   output );

When run.

instant = 2022-11-18T19:27:22.561715Z
millisSinceEpoch = 1668799642561
output = Saturday, November 19, 2022 at 4:27:22 AM Japan Standard Time

Android 26 carries an implementation of the java.time classes. For earlier Android, the latest tooling provides access to most of the java.time functionality via “API desugaring”.

  • Related