3

For a Java learner, this simple question is a headache. I'm quite sure a simple answer would help beginners.

So here are the requirements:

  • Print at the console Today is May 22, 2014 and it is 2:04 pm
  • Where the date and time are the current ones as displayed by the local system (local time)
  • Where the date/time format used is compliant with the JVM locale, meaning that for me in France this would print Today is 22 mai 2014 and it is 14:04
  • External libraries are ok only as an alternative, after providing a solution with standard APIs.

This seems not far from the "hello world" difficulty level, still I'm puzzled by the complexity of what what I've seen when searching for an answer.


Now just for reference, here are information about the suggestions I have found, and that drive me crazy:

  • Don't use Date, use Calendar, here.
  • Use Date and SimpleDateFormat, here.
  • Don't use java.util.{Calendar,Date}, here.
  • For the date part, use Calendar and set time components to zero, here.
  • Use only System.currentTimeMillis() to get date and time, here.

Edit: the solution provided by Michael:

Date now = new Date();
DateFormat dateFmt = DateFormat.getDateInstance(DateFormat.LONG);
DateFormat timeFmt = DateFormat.getTimeInstance (DateFormat.SHORT);
System.out.println("Today is "   + dateFmt.format(now) +
                   " and it is " + timeFmt.format(now));
mins
  • 6,478
  • 12
  • 56
  • 75
  • 1
    So the format "22 mai 2014" - is that fixed, or should be the locale-default date format (short, long, whatever). It's not clear why the suggestion of "Use `Date` and `SimpleDateFormat`" has driven you crazy... – Jon Skeet May 22 '14 at 10:36
  • What doesn't? You haven't shown us the code you've tried. – Jon Skeet May 22 '14 at 10:40
  • Have you checked out the Calendar JavaDocs? Google search Calendar JavaDocs Oracle and you should find the right page. Read that and you'll understand what you need to do. If you are still unsure, reply and I will give a proper answer. – TheBrenny May 22 '14 at 10:45
  • @mastercork889: The only solution I can see doesn't provide localization. It is getting a Calendar instance and obtaining the 5 date/time components using calls like get(Calendar.DAY_OF_MONTH) or getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()), and then printing them with printf. What would be the solution supporting localization? – mins May 22 '14 at 15:17
  • 1
    @Approachingminimums: You didn't say what level of localization you wanted. `SimpleDateFormat` *will* localize in terms of knowing the short/medium/full patterns for dates and times. If you want to localize a whole *sentence*, that's a different matter - and your sample external output of "Today is 22 mai 2014 and it is 14:04" seems to go against that. Basically your requirements are *far* from clear. – Jon Skeet May 22 '14 at 15:36
  • @Approachingminimums: Right, so you want the locale-specific date format as well as the locale-specific format symbols. Use `DateFormat.getDateInstance`. (I'd forgotten that that's the way you do it in Java; in .NET you just specify a different format specifier.) – Jon Skeet May 22 '14 at 15:59
  • This question was asked at a critical time just a few months after Java 8 and with it [java.time, the modern Java date and time API,](https://docs.oracle.com/javase/tutorial/datetime/) came out. So many of the answers from back then reflect that fact that java.time was not yet in widespread use. Today no one should be in doubt that it is the answer to the question. – Ole V.V. May 05 '21 at 15:13

6 Answers6

3

java.time

The legacy date-time API (java.util date-time types and their formatting API, SimpleDateFormat) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.

Solution using modern date-time API:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String args[]) {
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("'Today is' dd MMM uuuu 'and it is' HH:mm", Locale.FRENCH);
        LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.println(dtf.format(ldt));
    }
}

Output:

Today is 05 mai 2021 and it is 11:50

Notes:

  1. Replace Locale.FRENCH with Locale.getDefault() if your JVM already has Locale.FRENCH set as the locale.
  2. Replace ZoneId.of("Europe/Paris") with ZoneId.systemDefault() or simply use LocalDateTime.now() if your JVM already has Europe/Paris set as the timezone.

For localization of the date and time formats too you may do like this:

        DateTimeFormatter dtfDate = DateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);
        DateTimeFormatter dtfTime = DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
        
        ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Paris"));
        System.out.format("Today is %s and it is %s%n",
                zdt.format(dtfDate), zdt.format(dtfTime));

Example output with default locale Locale.FRENCH:

Today is 5 mai 2021 and it is 19:08

Example with Locale.US:

Today is May 5, 2021 and it is 7:11 PM

The latter snippet also features another difference, the use of ZonedDateTime instead of LocalDateTime. It would be advantageous under the following circumstances:

  1. If you wanted (now or at a later time) to give output in FULL format, which includes time zone and therefore requires a ZonedDateTime.
  2. If at any time you wanted to use the date-time object for anything else than printing, it’s safest that it knows its own time zone. This can prevents a range of potential errors.

Learn more about the 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.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
2

You definitely want to use new Date() to get the current time.

Since you want localized formatting, use the getDateInstance() and getTimeInstance() factory methods of java.text.DateFormat to get formatter objects. Look at the overloaded versions for more control of the formatting style.

That's all you need.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • This is the solution, it prints 'Today is 22 mai 2014 and it is 13:40' (with LONG for date format, and SHORT for time format.) Thanks a lot. What do you mean by by "more control" with overloaded method, could you give me an example? – mins May 22 '14 at 11:43
  • @Approachingminimums: I meant that you get the choice between LONG, SHORT, MEDIUM and FULL style. – Michael Borgwardt May 22 '14 at 11:52
  • You definitely **don’t** want to use the `Date` class. FYI it’s poorly designed and long outdated. And `DateFormat` is even worse, a notorious troublemaker of a class. You will much prefer to use `ZonedDateTime`or another class from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. May 05 '21 at 15:10
2

Try this (which uses the default JVM locale):

DateFormat df = new SimpleDateFormat("'Today is 'MMM dd, yyyy' and it is 'HH:mm");
System.out.println(df.format(new Date()));

If you need a different locale you can force it like follows:

DateFormat df = new SimpleDateFormat("'Today is 'MMM dd, yyyy' and it is 'HH:mm", new Locale("en"));
System.out.println(df.format(new Date()));

Or you can update the locale of the JVM to override the system one: how do I set the default locale for my JVM?

Community
  • 1
  • 1
tom
  • 2,735
  • 21
  • 35
  • This is for sure the simplest I've seen so far. Thanks for that (also to Jens). However this will not print according to the locale. – mins May 22 '14 at 11:06
  • What part needs to be localized. When I print it, I get the month in dutch: Today is mei 22, 2014 and it is 13:09 PM. It is using the locale of my system. – tom May 22 '14 at 11:11
  • What would be correct for me is: Today is 22 mai 2014 and it is 14:04. What I obtain is: Today is mai 22, 2014 and it is 13:13 PM – mins May 22 '14 at 11:14
  • Still 'mai 22, 2014' (US / Dutch way) is not the same than '22 mai 2014' (French way) – mins May 22 '14 at 11:32
  • Your second (edited) version using SimpleDateFormat(String pattern, Locale locale) doesn't work either. From the javadoc: "@param locale - the locale whose date format symbols should be used" is not clear to me, and I can't find a good explanation. I assume the locale will provide localized format abbreviations to be used in the pattern instead of the std ones, e.g. A instead of Y for the year (which translates to année in FR). Somehow confusing. – mins May 22 '14 at 15:28
1

Try this code

  DateFormat df = new SimpleDateFormat("MMM dd, yyyy");
  DateFormat tf = new SimpleDateFormat("HHH:mm aa");
  Date date = new Date();
  System.out.println("Today is "+df.format(date)+" and it is "+tf.format(date));

df is the Formater for date, tf is the formater for the time string.

Jens
  • 67,715
  • 15
  • 98
  • 113
0

Mixing English words with localized date-time values seems peculiar. But here you go.

Avoid java.util.Date/Calendar

The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use a decent date-time library instead, such as Joda-Time or the new java.time package in Java 8.

Time Zone

Your question ignores the crucial issue of time zone.

Joda-Time

Example code in Joda-Time 2.3.

DateTimeZone timeZoneParis = DateTimeZone.forID( "Europe/Paris" );
DateTime nowParis = DateTime.now( timeZoneParis ); // Paris time, but Québécois style.
String datePortion = DateTimeFormat.forStyle( "M-" ).withLocale( Locale.CANADA_FRENCH ).print( nowParis );
String timePortion = DateTimeFormat.forStyle( "-S" ).withLocale( Locale.CANADA_FRENCH ).print( nowParis );
// Tweak the Style argument: 'S' for short style, 'M' for medium, 'L' for long, and 'F' for full. A date or time may be omitted by specifying a style character '-'.
System.out.println( "Today is " + datePortion + " and it is " + timePortion );
Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
  • The solution with JDK classes Date and DateFormat is somehow more simple, based on my requirements. But I understand that for more complex date/time operations and JDK 7 or less, Joda-Time would have significant advantages, thanks. To answer your comments: this is an example, in real life I'd externalize strings in a resource bundle to have consistent i18n. Regarding ignored time zone, I don't get your point, bullet #2 of the reqs seems to address that. – mins May 24 '14 at 10:26
  • (A) The JVM's default time zone defaults to the host environment's time zone but can be overridden by a call to TimeZone.setDeault. Doing so affects all code running in all threads in that JVM. Though ill-advised, people do do this as seen in frequenct suggestions here on StackOverflow. (B) If you truly do want to use the JVM's default time zone, make an explicit call to `getDefault` to make your intentions clear and to make your code self-documenting. – Basil Bourque May 24 '14 at 15:25
  • As for using the bundled java.util.Date and .Calendar classes, even Sun/Oracle has given up on those classes. I strongly suggest you do too. – Basil Bourque May 24 '14 at 15:28
  • (A) interesting ;-) and (B) is a very good suggestion then. In the selected answer at http://stackoverflow.com/questions/8809098/how-do-i-set-the-default-locale-for-my-jvm it is explained how to change the JVM default locale and that subsequent calls to Locale.getDefault() will return the "new" locale just set. So is there really a possibility to retrieve the old locale without storing it manually prior to the change? Thanks for your time. – mins May 24 '14 at 16:59
  • @mins (A) You are asking a whole new question, an interesting one, but should be posted as a new Question on StackOverflow if it does not already exist: Is there a way to access the TimeZone and Locale of the host OS/environment rather than the current default set within the JVM, in other words, the TimeZone & Locale set when the JVM first launched? (B) Regardless of the answer to that question, ultimately the wisest solution about TimeZone and Locale is to ask the user what they want rather than assume. For example, I may be in Paris but my office app to display in Seattle timezone/Locale. – Basil Bourque May 24 '14 at 21:26
  • I have misunderstood your first comment. I thought your (B) suggestion was for retrieving the initial JVM/system locale. Now I see you were talking about improving self-documentation, not changing the code. Sorry for the mistake. – mins May 24 '14 at 21:44
-1

Go ahead and use Date and SimpleFormat. To get things in the format that you need, you can always call a String.split( X ) on the date string to get at the different pieces you need. Once you have those pieces it should be relatively simple to print the info you need

Kyte
  • 834
  • 2
  • 12
  • 27