0

New to spring-boot.

I'm trying to parse the properties from the file with annotation @ConfigurationProperties. I'm able to parse the fields other than date field.

issue is My property file has only time without date. i.e. date=09:30:00.

I'm able to parse it with @DateTimeFormat(pattern = "HH:mm:ss"). But the issue is, it is giving date as date=Thu Jan 01 09:30:00 GST 1970.

I would like to get the date as todays date with time 09:30:00. Is it possible ?

@ConfigurationProperties
public class Config {

    private int id;
    
    private int version;
        
    @DateTimeFormat(pattern = "HH:mm:ss")
    private Date date;
    
}

Property

id=12
version=2
date=09:30:00
Kuldeep.b
  • 35
  • 2
  • 8
  • 1
    No. As you are parsing without a date it will do so. If it is only a time representation why not just use `LocalTime` instead of a `Date`? – M. Deinum Mar 16 '21 at 13:41
  • Thanks for the reply. Because I'll need a date as well to do some computation like add 1 working day and so on. – Kuldeep.b Mar 17 '21 at 05:35
  • 1
    Then do that with a `LocalDateTime` and use the given Time as an input for that when you need. – M. Deinum Mar 17 '21 at 06:40

3 Answers3

6

Why not use a type that represents time only?

    @DateTimeFormat(pattern = "HH:mm:ss")
    private LocalTime time;

    public LocalDateTime getDate() {
        return LocalDateTime.of(LocalDate.now(), time);
    } 
crizzis
  • 9,978
  • 2
  • 28
  • 47
2

The output you are getting is as expected because a string is parsed into java.util.Date using a SimpleDateFormat which defaults the date-time to January 1, 1970, 00:00:00 GMT.

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class Main {
    public static void main(String[] args) throws ParseException {
        String text = "09:30:00";
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        Date date = sdf.parse(text);
        System.out.println(date);
    }
}

The output in my timezone (Europe/London):

Thu Jan 01 09:30:00 GMT 1970

Note that the java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it. The java.util date-time API and their formatting API, SimpleDateFormat are not only outdated but also error-prone because of many such things. It is recommended to stop using them completely and switch to the modern date-time API1.

Given below are a couple of options:

  1. Recommended: Use LocalTime which truly represents time.
    @DateTimeFormat(pattern = "HH:mm:ss")
    private LocalTime time;
  1. Dirty way: Declare your field as a String and parse it in your business logic making it error-prone and dirty.
    private String time;

I strongly recommend NOT to go with the second option.

A quick demo using LocalTime:

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String text = "9:30:00";

        // The optional part can be put inside square bracket
        DateTimeFormatter dtfInput = DateTimeFormatter.ofPattern("H:m[:s]", Locale.ENGLISH);
        LocalTime time = LocalTime.parse(text, dtfInput);

        // Default implementation of LocalTime#toString omits the seconds part if it is zero
        System.out.println(time);

        // Custom output
        DateTimeFormatter dtfOutput = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.ENGLISH);
        String formatted = dtfOutput.format(time);
        System.out.println(formatted);
    }
}

Output:

09:30
09:30:00

Learn more about the modern date-time API from Trail: Date Time.


1. 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.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
0

Don't use old and obsolete class Date. Look into package java.time and in particular in your case - class LocalTime.

change your code to: @ConfigurationProperties public class Config {

private int id;

private int version;
    
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm:ss")
private LocalTime date;

}

This should work. You may need to add the following dependency:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.6.0</version>
</dependency>

This is modified answer from this question: Spring Data JPA - ZonedDateTime format for json serialization

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
  • I think @DateTimeFormat(pattern = "HH:mm:ss") would do the same thing. Why complicate it by adding additional dependency? – Kuldeep.b Mar 17 '21 at 05:38
  • @Kuldeep.b - I don't know if @DateTimeFormat(pattern = "HH:mm:ss") will work. The simplest way to find out is to try. I know that what I wrote in my answer works for sure. As for dependency, you need it in any case. It might be that in some later versions of JDK it is already inside so you may not need to add it explicitly. In any case, I would be interested to know which one worked for you in the end. So write a comment if you will. – Michael Gantman Mar 17 '21 at 09:47
  • Thanks for the comment, Answer given by crizzis (https://stackoverflow.com/a/66656415/10673161) worked for me. – Kuldeep.b Mar 17 '21 at 12:10