Hot questions for Using Joda-Time in joda convert

Top Java Programmings / Joda-Time / joda convert

Question:

I want to convert 21022019 to 2019-02-21, but some reason I am not able to convert.

import org.joda.time.LocalDate;
import org.joda.time.LocalDateTime;
import org.joda.time.format.DateTimeFormat;

public class StringToLocalDate {
    public static void main(String[] args) {
        System.out.println(convert("21022019"));
    }

    static LocalDate convert(String date) {
        LocalDateTime ldt;
        ldt = LocalDateTime.parse(date, DateTimeFormat.forPattern("YYYY-MM-dd"));
        return LocalDateTime.now().toLocalDate();
    }
} 

Answer:

If you are using Java 8, you can use the native Java Time library that was developed by the same guy (Stephen Colebourne) who created Joda time. It's pretty easy to parse and display dates in various formats.

Your main issue seems to be that you are treating your expected object as a LocalDateTime, but there is no time present. This is essentially throwing your code through a runtime error that states that you need to include time, so you should use a LocalDate instead.

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class StringToLocalDate {
    public static String DATE_FORMAT_INPUT = "ddMMyyyy";
    public static String DATE_FORMAT_OUTPUT = "yyyy-MM-dd";

    public static void main(String[] args) {
        System.out.println(formatted(convert("21022019")));
    }

    public static String formatted(LocalDate date) {
        return date.format(DateTimeFormatter.ofPattern(DATE_FORMAT_OUTPUT));
    }

    public static LocalDate convert(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormatter.ofPattern(DATE_FORMAT_INPUT));
    }
}

If you need to use a Java version before 1.8, you can use the following. It is very similar.

import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;

public class StringToLocalDate {
    public static String DATE_FORMAT_INPUT = "ddMMyyyy";
    public static String DATE_FORMAT_OUTPUT = "yyyy-MM-dd";

    public static void main(String[] args) {
        System.out.println(formatted(convert("21022019")));
    }

    public static String formatted(LocalDate date) {
        return date.toString(DateTimeFormat.forPattern(DATE_FORMAT_OUTPUT));
    }

    public static LocalDate convert(String dateStr) {
        return LocalDate.parse(dateStr, DateTimeFormat.forPattern(DATE_FORMAT_INPUT));
    }
}

Question:

I read many posts at SO and tested most of them. None of them is working for me. Here is my code:

DateTimeZone fromTimeZone = DateTimeZone.forID("America/New_York");
DateTimeZone toTimeZone = DateTimeZone.forID("US/Central");  
Date now = new Date();        
DateTime dateTime = new DateTime(now, fromTimeZone); 
DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(dateTime.toDate() + "--" + newDateTime.toDate());

Here is what I got in print:

Tue Aug 22 13:08:13 EDT 2017--Tue Aug 22 13:08:13 EDT 2017

I am hoping to display "Tue Aug 22 12:08:13 CDT 2017" for the second time zone.


Answer:

A java.util.Date doesn't have timezone information. Joda's DateTime has, but it's wrapped into a Chronology to translate this instant to "human readable" date/time fields.

But in the end, both objects just represent points (instants) in the time-line.

Just check the values of dateTime.getMillis(), newDateTime.getMillis(), dateTime.toDate().getTime() and newDateTime.toDate().getTime(). They will all be exactly the same, and this value represents the number of milliseconds since epoch (1970-01-01T00:00Z).

The timezone passed to the DateTime object just affects the output of toString() (when this milliseconds value is "translated" to a local date and time), but it doesn't change the milliseconds value itself. So if you do:

DateTime dateTime = new DateTime(now, fromTimeZone);
System.out.println(dateTime);

It will print the date and time that's equivalent to the milliseconds value, but converted to the fromTimeZone (America/New_York):

2017-08-22T13:33:08.345-04:00

The withZone method just sets to a different timezone, but keeps the same milliseconds value:

DateTime newDateTime = dateTime.withZone(toTimeZone);
System.out.println(newDateTime);

The code above keeps the instant (the milliseconds value), but prints the equivalent date and time in the toTimeZone (US/Central):

2017-08-22T12:33:08.345-05:00

The .toDate() method returns a java.util.Date, which just contains the same milliseconds value, and no timezone information. Then, System.out.println implicity calls Date::toString() method, and this converts the milliseconds value to the JVM's default timezone. In this case both will be:

Tue Aug 22 13:33:08 EDT 2017

Because both dates represent the same instant (the same number of milliseconds since epoch).


If you want to get a String that contains the date in a specific format, you can use a org.joda.time.format.DateTimeFormatter:

DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
System.out.println(fmt.print(new DateTime(DateTimeZone.forID("US/Central"))));

There's no need to convert dates objects, because actually no conversion is really happening: all methods above don't change the milliseconds value.

Also note that I used a java.util.Locale to make sure the month and day of week are in English. If you don't specify a locale, the JVM 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 better to always specify it).

Then I get the current date and set the timezone to be used when printing it. Note that you can get a DateTime directly, there's no need to create a java.util.Date.

The output will be:

Tue Aug 22 12:33:08 CDT 2017

To get exactly the same output you want (with both dates), you can do:

DateTimeFormatter fmt = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy").withLocale(Locale.ENGLISH);
DateTime nowNy = new DateTime(DateTimeZone.forID("America/New_York"));
DateTime nowCentral = nowNy.withZone(DateTimeZone.forID("US/Central"));
System.out.println(fmt.print(nowNy) + "--" + fmt.print(nowCentral));

The output will be:

Tue Aug 22 13:33:08 EDT 2017--Tue Aug 22 12:33:08 CDT 2017


Java new Date/Time API

Joda-Time is in maintainance mode and 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 don't want to or can't migrate from Joda to another API, you can desconsider 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 relevant classes are DateTimeFormatter (to format the date to a String in a specific format), ZonedDateTime (which represents a date and time in a specific timezone) and a ZoneId (which represents a timezone):

// formatter - use English locale for month and day of week
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);

// current date/time in New York timezone
ZonedDateTime nowNy = ZonedDateTime.now(ZoneId.of("America/New_York"));
// convert to another timezone (US/Central)
ZonedDateTime nowCentral = nowNy.withZoneSameInstant(ZoneId.of("US/Central"));

// format dates
System.out.println(fmt.format(nowNy) + "--" + fmt.format(nowCentral));

The output is the same as above.

Question:

I need timestamp format for my dates in database. For now i have joda.Datetime in database , but also in my restApi application.

I tried to create a new column , and converted the existing joda.Datetime in the other column time.LocalDateTime. Also I replaced in all code joda.DateTime with time.LocalDateTime.

It works, but when i make a get call in postman, i received a json like:

{
seconds: x1,
minutes: x2,
hours: x3,
days: x4,
........
}

I think i need a convertor, to show the timestamp as "dd-mm-yy hh-mm-ss"

I want to have timestamp format in database to be able to execute SQL standard operation and named queries on time.

In my database I have bytea type for dates. I use PostgreSQL with DBeaver.

Is this the right way, or you could recommend me another option?


Answer:

Is this the right way, or you could recommend me another option?

Without experience with PostgreSQL I should say that bytea is the wrong datatype for your dates or timestamps. timestamp with time zone is good and supports SQL operations and queries. It further has the advantage that you can store OffsetDateTime (perhaps even Instant, I am not sure) directly, so you avoid formatting your timestamp for storing it. That’ll be recommended.

For a time stamp to be a time stamp date and time of day is not enough. Date and time of day will be interpreted differently in different time zones (and is even ambiguous in the fall when summer time ends and the clocks are turned backward). As far as I have understood timestamp with time zone will make sure that time stamps are stored in UTC, so will be unambiguous points in time. In Java the Instant class represents a point in time independently of time zone, so is good for timestamps. Some JDBC drivers allow you to store an Instant directly into a timestamp with time zone column, others require you to convert to OffsetDateTime first. In the latter case use

OffsetDateTime dateTimeForDatabase = yourInstant.atOffset(ZoneOffset.UTC);

Edit: Please note that the with time zone bit is a bit of a lie, as @Jon Skeet points out in a comment. The database doesn’t store a time zone or offset, it only makes sure that dates and times are stored in UTC for removing ambiguity about the point in time.

Link: Date/Time Types in the PostgreSQL docs

Question:

I have Thymeleaf code (this code need for me to add parameter for JQuery - DatePicker):

<table th:attr="data-availible-dates=${defoultSetting.avalibleDates}">

now page looks like:

data-availible-dates="[2014-01-09T00:00:00.000, 2014-01-14T00:00:00.000, 2014-01-10T00:00:00.000, 2014-01-23T00:00:00.000, 2014-01-15T00:00:00.000, 2014-01-06T00:00:00.000, 2014-01-24T00:00:00.000, 2014-01-20T00:00:00.000, 2014-01-16T00:00:00.000, 2014-01-21T00:00:00.000, 2014-01-08T00:00:00.000, 2014-01-22T00:00:00.000, 2014-01-17T00:00:00.000, 2014-01-13T00:00:00.000]"

but I wont to convert to milliseconds like this example:

data-availible-dates="[1451170800000, 1452380400000, 1452466800000, 1452553200000]"

Can I use Thymeleaf and make something similar to JsonDeserializer.. which will be convert data to milliseconds before build the page ?

Result:

I decided to send the list of milliseconds, and second I am using now next code in case when need to add variables from server side to JS:

<script type="text/javascript" th:inline="javascript">
/*<![CDATA[*/
    var avalibleDates = /*[[${defoultSetting.avalibleDates}]]*/;
/*]]>*/
</script>

Answer:

Hmm, doesn't look like there's a built-in function to do that in Thymeleaf. But you can write simple Javascript function to convert DateTime to Time in milliseconds, using function below:

var myDate = new Date("2012-02-10T13:19:11+0000");
var result = myDate.getTime();

On the other hand, if you need to have time in milliseconds, why you will not convert it on Java side and send processed final variable set (containing times in milliseconds) to Thymeleaf?

Question:

Could someone tell me what I am doing wrong for getting this StackOverFlowError with Joda library?

Here the code implyed:

  public Integer getAge() {
    if ( getBirthDate() != "//" ) {
        try {
            LocalDate birth = LocalDate.parse( getBirthDate(), DateTimeFormat.forPattern( "dd/MM/yyyy" ) );//Error raised here
            DateTime today = new DateTime();
            if ( today.getMonthOfYear() >= birth.getMonthOfYear() ) {
                age = today.getYear() - birth.getYear();
            } else {
                age = today.getYear() - birth.getYear() - 1;
            }
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }
    return age;
}

Here where I call this method :

@Override
public boolean equals( Object obj ) {

    if ( this == obj ) {
        return true;
    }
    if ( obj == null ) {
        return false;
    }
    if ( !( obj instanceof Identite ) ) {
        return false;
    }

    Identity other = (Identity) obj;
    EqualsBuilder equalsBuilder = new EqualsBuilder();

    equalsBuilder.append( getAge(), other.getAge() );//here the call
    return equalsBuilder.isEquals();
}

I am using the getter method for Hibernate.

How to avoid this error?

The stack trace :

java.lang.StackOverflowError
at org.joda.time.chrono.BasicChronology.getYear(BasicChronology.java:426)
at org.joda.time.chrono.BasicGJChronology.setYear(BasicGJChronology.java:180)
at org.joda.time.chrono.BasicYearDateTimeField.setExtended(BasicYearDateTimeField.java:92)
at org.joda.time.format.DateTimeParserBucket$SavedField.set(DateTimeParserBucket.java:568)
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:447)
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:411)
at org.joda.time.format.DateTimeFormatter.parseLocalDateTime(DateTimeFormatter.java:887)
at org.joda.time.format.DateTimeFormatter.parseLocalDate(DateTimeFormatter.java:844)
at org.joda.time.LocalDate.parse(LocalDate.java:179)
at com.home.entities.Identity.getAge(Identite.java:127)
at com.home.entities.Identity.equals(Identite.java:185)

EDIT Joda dependencies and getBirthDate():

   <dependency>
        <groupId>joda-time</groupId>
        <artifactId>joda-time</artifactId>
       <version>2.9.7</version> 
    </dependency>
    <dependency>
        <groupId>org.joda</groupId>
        <artifactId>joda-convert</artifactId>
        <version>1.8.1</version>
    </dependency>

The method is:

public String getBirthDate() {
    if ( getBirthDay() != null && getBirthMonth() != null && getBirthYear() != null ) {
        birthDate= getBirthDay()+ "/" +  getBirthMonth() + "/" + getBirthYear();
    }
    return birthDate;
}

Answer:

I found the reason of this exception, I just forgot to load the required data from database.