简体   繁体   中英

Java 8 Setting global time formatters

I want to set my own DateTimeFormatter as the global formatter. When I do the following line:

ZonedDateTime.now();

I get:

2016-03-30T08:58:54.180-06:00[America/Chicago]

If I do this:

ZonedDateTime.now().format(DateTimeFormatter.RFC_1123_DATE_TIME)

I get:

Wed, 30 Mar 2016 9:00:06 -0600

I want what's printed above but with am/pm so I made my custom formatter and printed out the time like so:

DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss a Z");

ZonedDateTime.now().format(FORMATTER);

Which gave me:

Wed, 30 Mar 2016 9:00:06 AM -0600

But I use this .now() method everywhere for logging purposes and I dont want to define the formatter everywhere in the code. Is there a way to configure the formatter as the default format to use when calling the .now() method? I'm thinking like spring bean configuration method or something.....

You could simply declare a constant in a class:

class UtilsOrWhatever {
  public static final DateTimeFormater RFC_1123_DATE_TIME_AM_PM = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy hh:mm:ss a Z");
}

and simply use in your code:

ZonedDateTime.now().format(RFC_1123_DATE_TIME_AM_PM); //needs a static import

Alternatively, with pure Java EE 7, you could create a DateTimeFormatter Producer with @Produces and then simply @Inject it.

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Produces;

@ApplicationScoped
public class RfcFormatterProducer {
  @Produces
  private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy hh:mm:ss a Z");
}

In your code:

@Inject DateTimeFormatter rfc;

You could also give it a name like in the link above if you have several formatters.

Let me first explain why you are getting what you are getting when you don't call the format. The toString is being called on the ZonedDateTime which in turn calls the toString on on DateTime and Offset, which calls toString on LocalDate and LocalTime. These toStrings do NOT use formatters, so even if you could specify a "default" formatter it would not be called when implicitly converting a ZonedDateTime to a string.

There are many ways to make producing that formatted string easier. One way would be a utility class that you would swap out for in all of your log statements. I don't necessarily suggest the following, but it most closely fits what you are asking:

public class MyAwesomeUtility {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss a Z");

    public static String getFormattedZonedDateTime() {
        return ZonedDateTime.now().format(FORMATTER);
    }
}

The following is not an option as ZonedDateTime is final as pointed out by @assylias. Leaving this here in any case.

If you really wanted to do what you asked in the question, which is overwrite the now method to return an object that would give a the specified format when toString was called you would have to do something like the following (NOTE: THIS IS AN ANTIPATTERN. DON'T ACTUALLY DO IT):

public class DefaultFormattedZonedDateTime extends ZonedDateTime {
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss a Z");
    @Overwrite
    public String toString() {
        this.format(FORMATTER);
    }
}

Then since now on ZonedDateTime is static and still returns ZonedDateTime you would have to use AspectJ (you can't around AOP a static method with spring alone) to have the now return this new object instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM