# Time offset between two dates

**URL:** <https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531>\
**Category:** Support\
**Created:** [July 26, 2021, 4:06pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531 "2021-07-26T16:06:30Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [July 26, 2021, 4:06pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/1 "2021-07-26T16:06:30Z")

</div>

Hello. As I understood, there is a problem with adequate date classes in Java. So, I need to calculate a time offset between two `LocalDateTime`s. I’m doing it simple:

```auto
val dur = Duration.between(dateUtcStart, localDateTime)

```

But how can I convert this duration to a normalized string like `+10:30` or `-01:30`? There is a `Kotlin` `Duration` class but I can’t recognize if its methods help.

I also have a dirty manual method:

```auto
val tsLocalDateTime = Timestamp.valueOf(localDateTime).time
val dif = tsLocalDateTime - startTs
val tsOffset = LocalTime.ofInstant(Instant.ofEpochMilli(dif), ZoneOffset.systemDefault())
val tzString = if (tsOffset.toSecondOfDay() > 0) "+$tsOffset" else tsOffset.toString()

```

But it doesn’t work with negative dates (`tsOffset.toSecondOfDay()` is always \> 0).

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [July 26, 2021, 7:49pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/2 "2021-07-26T19:49:44Z")

</div>

> [@Psijic](#):
>
> As I understood, there is a problem with adequate date classes in Java

I’m not sure what is the problem you talk about.

I think Java time API lacks a duration formatter, but still it is pretty easy to format `Duration` manually, using methods like `toHoursPart()`, `toMinutesPart()`. Did you try this?

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [July 27, 2021, 7:23am UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/3 "2021-07-27T07:23:30Z")

</div>

This works ok with a positive value but need to add modifications for a negative one. And also I need to add the second digit if the hours or minutes contain only one. So, I’m curious: is there no default method for it in whole Java/Kotlin?  
The current code is:

```auto
val offset = if (min >= 0) "+${dur.toHoursPart()}:${dur.toMinutesPart()}"
else "${dur.toHoursPart()}:${-dur.toMinutesPart()}"

```

P.S. This is my original code, so I need to improve it and make work correctly:

```auto
fun parseDateTime(startTs: Long, endTs: Long, localizedDateTime: String): Pair<String, String> {
    val dateUtcStart = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTs), ZoneOffset.UTC)
    val dateUtcEnd = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTs), ZoneOffset.UTC)

    val formatter = DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .parseDefaulting(ChronoField.YEAR_OF_ERA, dateUtcStart.year.toLong())
        .append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
        .toFormatter(Locale.ENGLISH)

    val localDateTime = LocalDateTime.parse(localizedDateTime, formatter)

    val localTs = Timestamp.valueOf(localDateTime).time
    val tsOffset = LocalTime.ofInstant(Instant.ofEpochMilli(localTs - startTs), ZoneOffset.systemDefault())
    val tzString = if (tsOffset.toSecondOfDay() > 0) "+$tsOffset" else tsOffset.toString()

    val startDate = dateUtcStart.toString() + tzString
    val endDate = dateUtcEnd.toString() + tzString

    return Pair(startDate, endDate)
}

@Test
fun parseDateTime() {
    val pair1 = parseDateTime(1626998400000, 1627005600000, "Fri 23 Jul 10:30 am")
    val pair2 = parseDateTime(1626998400000, 1627005600000, "Thu 22 Jul 11:30 pm")

    // pass
    assertEquals("2021-07-23T00:00+10:30", pair1.first)
    assertEquals("2021-07-23T02:00+10:30", pair1.second)
    // fails
    assertEquals("2021-07-23T00:00-00:30", pair2.first)
    assertEquals("2021-07-23T02:00-00:30", pair2.second)
}

```

Where `startTs` - start of an event timestamp. `endTs` - end of this event timestamp. `localizedDateTime` is used to show the start time in the actual time zone (real city) while timestamps show time in UTC. I need to extract this timezone from `localizedDateTime` and add it to start and end string dateTimes (`start = "2021-07-23T00:00+10:30", end = "2021-07-23T02:00+10:30"`)

---

<div class="post-metadata">

**Author:** ![akurczak](https://avatars.discourse-cdn.com/v4/letter/a/f07891/32.png) [@akurczak](https://discuss.kotlinlang.org/u/akurczak)\
**Post date:** [July 27, 2021, 1:27pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/4 "2021-07-27T13:27:29Z")

</div>

If I understand correctly, `startTs` and `localizedDateTime` represent exactly the same event timestamp, but in different time zones - respectively UTC and some time zone, that’s local to the event, and your main interest is to retrieve the offset of the event-local time zone, is that right?  
If so, it seems that you may be interested in using `ZoneOffset` and `OffsetDateTime`

See your example adapted to use them. It seems to follow the formatting you want:

```run-kotlin
import java.time.Duration
import java.time.Instant
import java.time.LocalDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
import java.time.format.DateTimeFormatterBuilder
import java.time.temporal.ChronoField
import java.util.*

//sampleStart
fun parseDateTime(startTs: Long, endTs: Long, localizedDateTime: String): Pair<String, String> {
    val dateUtcStart = LocalDateTime.ofInstant(Instant.ofEpochMilli(startTs), ZoneOffset.UTC)
    val dateUtcEnd = LocalDateTime.ofInstant(Instant.ofEpochMilli(endTs), ZoneOffset.UTC)

    val formatter = DateTimeFormatterBuilder()
        .parseCaseInsensitive()
        .parseDefaulting(ChronoField.YEAR_OF_ERA, dateUtcStart.year.toLong())
        .append(DateTimeFormatter.ofPattern("E dd MMM hh:mm a"))
        .toFormatter(Locale.ENGLISH)

    val localDateTime = LocalDateTime.parse(localizedDateTime, formatter)

    val duration = Duration.between(dateUtcStart, localDateTime)
    val offset = ZoneOffset.ofTotalSeconds(duration.seconds.toInt())
    val startWithOffset = dateUtcStart.atOffset(offset)
    val endWithOffset = dateUtcEnd.atOffset(offset)

    return Pair(startWithOffset.toString(), endWithOffset.toString())
}

fun main() {
    val pair1 = parseDateTime(1626998400000, 1627005600000, "Fri 23 Jul 10:30 am")
    val pair2 = parseDateTime(1626998400000, 1627005600000, "Thu 22 Jul 11:30 pm")

    println(pair1)
    println(pair2)
}
//sampleEnd

```

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [July 27, 2021, 5:19pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/5 "2021-07-27T17:19:37Z")

</div>

Thanks. It looks like a successful solution.

---

<div class="post-metadata">

**Author:** ![gidds](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gidds/32/10865_2.png) [@gidds](https://discuss.kotlinlang.org/u/gidds)\
**Post date:** [July 27, 2021, 9:15pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/6 "2021-07-27T21:15:04Z")

</div>

> [@broot](#):
>
> > [@Psijic](#):
> >
> > As I understood, there is a problem with adequate date classes in Java
> 
> I’m not sure what is the problem you talk about.

Java certainly _did_ have problems. Java 1.0’s `Date` class was basically a toy, and while Java 1.1’s additional `Calendar` and related classes went some way to provide localisation, time zones, conversions, parsing/formatting, and the like, they’re still very clunky, limited, and fragile compared with a modern date API.

But 7 years ago, Java 8 added the `java.time` classes (inspired by JodaTime), which are much more flexible, useful, and well-thought-out. (Once you get the hang of them and understand some of the subtle distinctions, anyway. The wide use of immutability makes them harder to optimise for some high-throughput systems — but that’s a niche problem, and adds safety.)

So maybe OP’s information is simply out-of-date?

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [July 27, 2021, 9:19pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/7 "2021-07-27T21:19:19Z")

</div>

OP mentioned `LocalDateTime` and `Duration` specifically, so he/she meant the new time API.

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [July 28, 2021, 7:23am UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/8 "2021-07-28T07:23:18Z")

</div>

Actually, here

> As I understood, there is a problem with adequate date classes in Java.

I meant there is no single class in Java for convenient work with dates and time. There was `Date` and most of it is deprecated, and now there are multiple classes like `LocalDate, LocalDateTime, Calendar, TimeZone, ZoneOffset, Duration`, etc. that could be combined better.  
So, maybe I need to make a proposal in Kotlin design.

---

<div class="post-metadata">

**Author:** ![broot](https://avatars.discourse-cdn.com/v4/letter/b/a88e57/32.png) [@broot](https://discuss.kotlinlang.org/u/broot)\
**Post date:** [July 28, 2021, 7:33am UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/9 "2021-07-28T07:33:54Z")

</div>

There are multiple classes. because dates are pretty complicated thing. We had simple `Date` class in Java for many, many years and for most Java developers it was like: “DO NOT USE THIS!” long before it has been deprecated.

---

<div class="post-metadata">

**Author:** ![gidds](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/gidds/32/10865_2.png) [@gidds](https://discuss.kotlinlang.org/u/gidds)\
**Post date:** [July 28, 2021, 10:10pm UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/10 "2021-07-28T22:10:04Z")

</div>

There is no single class to work with dates/times, because there is no single type of date/time!

You might have a moment or 24-hour period in some specific place (known or unknown), or a space or moment on some calendar, or a single moment in time, or various other things. They may _look_ very similar, but they all _behave_ differently — so if a date/time API is going to handle them properly, it needs to know exactly what you mean. Otherwise you get into All Sorts Of Trouble the moment summer time starts or ends in your locale, or in some other locale that you deal with, or you talk to some database that’s expecting your UTC-based timestamp to be in the server’s time-zone, or have to look at historical data for a region whose rules about summer time changed recently, or deal with intervals that include leap seconds, or…

There are [many](https://youtu.be/-5wpm-gesOY) [awkward](https://youtu.be/D3jxx8Yyw1c) [corner](https://youtu.be/yRz-Dl60Lfc) [cases](https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/) [about](https://zachholman.com/talk/utc-is-enough-for-everyone-right) [dates](https://yourcalendricalfallacyis.com/) [and](https://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time) [times](https://infiniteundo.com/post/25509354022/more-falsehoods-programmers-believe-about-time), and `java.time` does a far better job than previous APIs of steering you away from them and doing what you expect. You just have to know which of its classes you should be using at each point. Yes, it’s a little complex, but most of that is _inherent_ complexity because dates and times _are_ complex — a simpler API is just hiding that under the carpet, from where it will come back to bite you, with nasty big pointy teeth.

---

<div class="post-metadata">

**Author:** ![Psijic](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/psijic/32/2227_2.png) [@Psijic](https://discuss.kotlinlang.org/u/Psijic)\
**Post date:** [July 31, 2021, 10:02am UTC](https://discuss.kotlinlang.org/t/time-offset-between-two-dates/22531/11 "2021-07-31T10:02:01Z")

</div>

Thanks. Is there a method to format two dates in a string (to make a range like “23:00 - 01:00”)?
