0

I want to create a java.util.Date object from microseconds. But i don't want to lose its precision microseconds to millisecond. Currently i am converting microseconds to Date object in the following way. If i pass microseconds to the Date constructor then it gives a wrong date like 56521-12-01.

long microSeconds = value.getTimestampValue();// This function returns a microseconds.
DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS);
long millis = TimeUnit.MILLISECONDS.convert(microSeconds, TimeUnit.MICROSECONDS);
String startDate = FORMAT.format(new Date(millis));

I don't want to convert microseconds to milliseconds. Is there is a method of API or java-8 utility where i can direct convert the microseconds to Date object?

The problem with this method is It remove the last three digits of microseconds to make it milliseconds then create a date object from milliseconds and parser just multiply its milliseconds part with 1000 to convert it into microseconds. In this way i lost a actul microsends.

8

5 Answers 5

7

tl;dr

Instant                                                  // Represent a moment as a count since the epoch reference of 1970-01-01T00:00Z.
.ofEpochSecond(                                          // Instantiate a `Instant` as a count of whole seconds plus fractional second.
    TimeUnit.MICROSECONDS.toSeconds( microseconds ) ,    // Count of whole seconds since the epoch reference.
    TimeUnit.MICROSECONDS.toNanos( microseconds )        // Calculate fractional second as a count of nanoseconds.
    - 
    TimeUnit.SECONDS.toNanos( 
        TimeUnit.MICROSECONDS.toSeconds( microseconds )
    ) 
)                                                        // Returns an `Instant`.
.toString()                                              // Generate text in standard ISO 8601 format.
.replace( "T" , " " )                                    // Replace a `T` with a SPACE for desired output format.
.replace( "Z" , "" )                                     // Remove the `Z` from the end, that indicates the date and time is in the context of UTC.   

Avoid legacy date-time classes

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

Furthermore, as others indicated, the legacy classes cannot accommodate microseconds, only milliseconds. Well, actually, the legacy class java.sql.Timestamp attempts to represent nanoseconds, but does so by way of a terrible hack that includes a fractional second in milliseconds and a fractional second of nanoseconds (a real mess).

java.time

Table of date-time types in Java, both modern and legacy

Sample data

For a demo, let's create the sample number of microseconds since the first moment of 1970 in UTC.

// Convert to microseconds. Use as input value to further code below.
Instant instantPrime = Instant.now().truncatedTo( ChronoUnit.MICROS ); // Drop any nanoseconds, to keep only microseconds.
long wholeSecondsPrime = instantPrime.getEpochSecond();
long nanoAdjustmentPrime = instantPrime.getNano();
long microseconds = 
    TimeUnit.SECONDS.toMicros( wholeSecondsPrime ) + 
    TimeUnit.NANOSECONDS.toMicros( nanoAdjustmentPrime )
;

Processing

Let's chop that count of microseconds into two parts, a number of whole seconds since 1970-01-01T00:00Z, and a fractional second as a number of microseconds.

// Convert from microseconds.
long wholeSeconds = TimeUnit.MICROSECONDS.toSeconds( microseconds );
long nanoAdjustment = TimeUnit.MICROSECONDS.toNanos( microseconds ) - TimeUnit.SECONDS.toNanos( wholeSeconds );

Put them back together again.

Instant instant = Instant.ofEpochSecond( wholeSeconds , nanoAdjustment );
boolean match = instant.equals( instantPrime );

Dump to console.

System.out.println( "instantPrime = " + instantPrime );
System.out.println( "wholeSecondsPrime = " + wholeSecondsPrime );
System.out.println( "nanoAdjustmentPrime = " + nanoAdjustmentPrime );

System.out.println( "microseconds = " + microseconds );

System.out.println( "wholeSeconds = " + wholeSeconds );
System.out.println( "nanoAdjustment = " + nanoAdjustment );
System.out.println( "instant = " + instant );

System.out.println( "match = " + match );

instantPrime = 2020-01-07T23:32:26.385565Z

wholeSecondsPrime = 1578439946

nanoAdjustmentPrime = 385565000

microseconds = 1578439946385565

wholeSeconds = 1578439946

nanoAdjustment = 385565000

instant = 2020-01-07T23:32:26.385565Z

match = true

Strings

Generate text representing the value of your Instant using standard ISO 8601 format.

String output = instant.toString() ;

2020-01-07T23:32:26.385565Z

Your desired format is close to that. Replace the T with a SPACE. And remove the Z, though be careful about that. Presenting date-time as text without indicating the time zone or offset-from-UTC can create ambiguity and confusing for the reader. I would recommend including the Z.

String output = instant.toString().replace( "T" , " " ).replace( "Z" , "" ) ;

2020-01-07 23:32:26.385565


About java.time

The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.

The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.

Where to obtain the java.time classes?

The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.

4
  • Thank you so much @Basil for insight details :) Commented Jan 8, 2020 at 5:12
  • I execute the same above code on my machine but it will print time differently. instantPrime = 2020-01-08T11:29:19.065Z wholeSecondsPrime = 1578482959 nanoAdjustmentPrime = 65000000 microseconds = 1578482959065000 wholeSeconds = 1578482959 nanoAdjustment = 65000000 instant = 2020-01-08T11:29:19.065Z match = true It only shows the time in milliseconds. Commented Jan 8, 2020 at 11:33
  • @KhalidShah Are you running Java 8? That version used an implementation of Clock that captured the current moment in milliseconds. Some implementations of Java 9 and later uses a new Clock that captures the current moment in microseconds. The java.time classes can represent nanoseconds, but conventional computer hardware clocks are not that accurate. Commented Jan 8, 2020 at 17:18
  • Yes i am using java 8 Commented Jan 8, 2020 at 17:19
5

You won't be able to do this using java.util.Date. From the API:

The class Date represents a specific instant in time, with millisecond precision.

2
  • My use case is only convert microseconds to` string representation of actual time` with microseconds precision. I can use other classes instead of Date. Commented Jan 7, 2020 at 16:51
  • 1
    @KhalidShah Then you should edit the question and say that.
    – Andreas
    Commented Jan 7, 2020 at 17:33
4
int seconds = (int) (microSeconds / 1_000_000);
int nanoSeconds = ((int) (microSeconds % 1_000_000)) * 1_000;
LocalDateTime t = LocalDateTime.ofEpochSecond(seconds, nanoSeconds, ZoneOffset.UTC);

String s = t.toString(); // with a T
s = t.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME); // with a T
s = t.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"));

Date has a milliseconds resolution. And the new time classes are far better, though need a bit more effort.

3
  • Missing () at int seconds = (int) (microSeconds / 1_000_000);
    – Andreas
    Commented Jan 7, 2020 at 17:49
  • 1
    Wrong class. The LocalDateTime class cannot represent a moment as it lacks the context of a time zone or offset-from-UTC. Change to OffsetDateTime. Commented Jan 7, 2020 at 18:16
  • Thanks @JoopEggen its really hepful :) Commented Jan 8, 2020 at 5:11
1

If your string contains milliseconds, then firstly we need to choose the appropriate pattern for it.

String date = "2021-11-15T07:45:28.655";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDate dt = LocalDate.parse(date, formattter);

It resolves your problem.

If it includes time zone as well, then you need to change the pattern again.

String date = "2021-11-15T07:45:28.655-08:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSz");
LocalDate dd = LocalDate.parse(date, formatter);
0

Just an alternative using LocalDateTime:

LocalDateTime date =
LocalDateTime.ofInstant(Instant.ofEpochMilli(millis), ZoneId.systemDefault());

However If you just want a sort of "well formatted timestamp" you can use just:

LocalDateTime.now()
1
  • The Questions is about microseconds, not milliseconds. Commented Jan 7, 2020 at 23:12

Not the answer you're looking for? Browse other questions tagged or ask your own question.