ThreeTen / threetenbp

Backport of functionality based on JSR-310 to Java SE 6 and 7. This is NOT an implementation of JSR-310.
http://www.threeten.org/threetenbp/
BSD 3-Clause "New" or "Revised" License
552 stars 139 forks source link

converting String Date (ISO_DATE) to Long #147

Closed Morons closed 3 years ago

Morons commented 3 years ago

I am trying to convert a String Date to Long

import org.threeten.bp.Instant.*
import org.threeten.bp.format.DateTimeFormatter

var result: Long = ISO_DATE.parse("1964-01-29", FROM).toEpochMilli()

However i get an ERROR

org.threeten.bp.format.DateTimeParseException: Text '1964-01-29' could not be parsed: Unable to obtain Instant from TemporalAccessor: DateTimeBuilder[, ISO, null, 1964-01-29, null], type org.threeten.bp.format.DateTimeBuilder
sschaap commented 3 years ago

You are parsing a date. Date values are not defined by any one moment in time; their start and/or end are dependent on a timezone. An epoch-milli defines a moment in time based on the milliseconds elapsed since 1970-01-01 0:00 UTC and therefore is a date-time value.

You need to determine what date-time value (related to your date) you wish to calculate the epoch-milli of. For example, perhaps you want to determine the epoch-milli value of the start of the day defined by your date, in the UTC timezone.

In that case, you might try something like:

// Parse the (textual) date input.
LocalDate date = LocalDate.parse("1964-01-29");
// Obtain an associated timezone-aware date-time value.
ZonedDateTime dateTime = date.atStartOfDay(ZoneOffset.UTC);
// Calculate epoch-milli of the associated moment-in-time.
long epochMilli = Instant.from(dateTime).toEpochMilli(); // = -186969600000L
Morons commented 3 years ago

@jodastephen Thank you You solved my Problem I wrote a nice converter testing forst if the String passed cn be a ISO Date/DateTime and then convet it to Long. I have not wrote Tests for it but those I us seem to work fine!

/**
 * Converts this instant to the number of milliseconds from the epoch of 1970-01-01T00:00:00Z.
 * [ISO_DATE] includes [ISO_OFFSET_DATE], [ISO_LOCAL_DATE], [ISO_ORDINAL_DATE] such as '2011-12-03' or '2011-12-03+01:00'.
 * [ISO_WEEK_DATE] such as '2012-W48-6'.
 * [ISO_INSTANT] such as '2011-12-03T10:15:30Z',
 * [ISO_DATE_TIME] such as '2011-12-03T10:15:30', '2011-12-03T10:15:30+01:00' or '2011-12-03T10:15:30+01:00[Europe/Paris]',
 * [ISO_LOCAL_DATE_TIME] such as '2011-12-03T10:15:30',
 * [ISO_ZONED_DATE_TIME] such as '2011-12-03T10:15:30+01:00[Europe/Paris]',
 * [ISO_OFFSET_DATE_TIME] such as '2011-12-03T10:15:30+01:00'
 * otherwise return current time in milliseconds from the epoch of 1970-01-01T00:00:00Z.
 * <p>
 * If this instant represents a point on the time-line too far in the future
 * or past to fit in a {@code long} milliseconds, then an exception is thrown.
 * <p>
 * If this instant has greater than millisecond precision, then the conversion
 * will drop any excess precision information as though the amount in nanoseconds
 * was subject to integer division by one million.
 * @param formatter [DateTimeFormatter]
 * For more complex formatters, a {@link DateTimeFormatterBuilder builder} is provided.
 * @return the current millisecond instant from this clock, measured from
 *  the Java epoch of 1970-01-01T00:00 UTC, not null
 * @return the current time in milliseconds from this clock, measured from
 *  the Java epoch of 1970-01-01T00:00 UTC, not null
 * @throws ArithmeticException if numeric overflow occurs
 */
fun String.toLongDate(formatter: DateTimeFormatter): Long {
    var result: Long = 0
    if (this.isNotBlank()) {
        when (formatter) {
            ISO_DATE -> if (isValidISODate(ISO_DATE)) {
                val zonedDateTime = LocalDate.parse(this).atStartOfDay(ZoneOffset.UTC)
                result = from(zonedDateTime).toEpochMilli()
            }
            ISO_WEEK_DATE -> if (isValidISODate(ISO_WEEK_DATE)) {
                val zonedDateTime = LocalDate.parse(this).atStartOfDay(ZoneOffset.UTC)
                result = from(zonedDateTime).toEpochMilli()
            }
            ISO_INSTANT -> if (isValidISODate(ISO_INSTANT)) {
                result = ISO_INSTANT.parse(this, FROM).toEpochMilli()
            }
            ISO_DATE_TIME -> if (isValidISODate(ISO_DATE_TIME)) {
                result = ISO_DATE_TIME.parse(this, FROM).toEpochMilli()
            }
            ISO_LOCAL_DATE_TIME -> if (isValidISODate(ISO_LOCAL_DATE_TIME)) {
                result = ISO_LOCAL_DATE_TIME.parse(this, FROM).toEpochMilli()
            }
            ISO_ZONED_DATE_TIME -> if (isValidISODate(ISO_ZONED_DATE_TIME)) {
                result = ISO_ZONED_DATE_TIME.parse(this, FROM).toEpochMilli()
            }
            ISO_OFFSET_DATE_TIME -> if (isValidISODate(ISO_OFFSET_DATE_TIME)) {
                result = ISO_OFFSET_DATE_TIME.parse(this, FROM).toEpochMilli()
            }
            else -> result = nowToLong()
        }
    } else {
        result = nowToLong()
    }
    return result
}

/**
 * Test if the given String Date/DateTime is a Valid ISO Date/DateTime
 * Only ISO Date/DateTime formats are tested the rest will result in false!
 * <p>
 * [ResolverStyle.STRICT] for 30, 31 days checking, and also leap year.
 * @param formatter [DateTimeFormatter]
 * For more complex formatters, a {@link DateTimeFormatterBuilder builder} is provided.
 * @return boolean whether the String Date is a Valid ISO Date/DateTime
 * @throws ArithmeticException if numeric overflow occur
 **/

fun String.isValidISODate(formatter: DateTimeFormatter): Boolean {
    return try {
        LocalDate.parse(
            this,
            formatter
                .withResolverStyle(ResolverStyle.STRICT)
        )
        true
    } catch (e: DateTimeParseException) {
        e.printStackTrace()
        false
    }
}

I am a Junior Programmer and cannot write UnitTests (Junit5) yet I only have one for the String.isValidISODate function