Skip to content

Commit fb1cde4

Browse files
authored
fix timestamp format (#204)
* fix date format issue * fix unit tests
1 parent 2be4602 commit fb1cde4

File tree

8 files changed

+57
-40
lines changed

8 files changed

+57
-40
lines changed

android/src/test/java/com/segment/analytics/kotlin/android/EventsFileTests.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ import com.segment.analytics.kotlin.core.TrackEvent
66
import com.segment.analytics.kotlin.core.emptyJsonObject
77
import com.segment.analytics.kotlin.core.utilities.EncodeDefaultsJson
88
import com.segment.analytics.kotlin.core.utilities.EventsFileManager
9-
import com.segment.analytics.kotlin.core.utilities.dateTimeNowString
9+
import com.segment.analytics.kotlin.core.utilities.SegmentInstant
1010
import io.mockk.every
11-
import io.mockk.mockkStatic
11+
import io.mockk.mockkObject
1212
import kotlinx.coroutines.test.runTest
1313
import kotlinx.serialization.encodeToString
1414
import kotlinx.serialization.json.buildJsonObject
@@ -32,10 +32,8 @@ class EventsFileTests {
3232
private val directory = File("/tmp/analytics-android-test/")
3333

3434
init {
35-
mockkStatic(Instant::class)
36-
mockkStatic(::dateTimeNowString)
37-
every { dateTimeNowString() } returns Date(0).toInstant().toString()
38-
every { Instant.now() } returns Date(0).toInstant()
35+
mockkObject(SegmentInstant)
36+
every { SegmentInstant.now() } returns Date(0).toInstant().toString()
3937
}
4038

4139
@BeforeEach

core/src/main/java/com/segment/analytics/kotlin/core/Events.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.segment.analytics.kotlin.core
22

3-
import com.segment.analytics.kotlin.core.utilities.dateTimeNowString
3+
import com.segment.analytics.kotlin.core.utilities.SegmentInstant
44
import kotlinx.serialization.DeserializationStrategy
55
import kotlinx.serialization.SerialName
66
import kotlinx.serialization.Serializable
@@ -80,7 +80,7 @@ sealed class BaseEvent {
8080
}
8181

8282
internal fun applyBaseData() {
83-
this.timestamp = dateTimeNowString()
83+
this.timestamp = SegmentInstant.now()
8484
this.context = emptyJsonObject
8585
this.messageId = UUID.randomUUID().toString()
8686
}

core/src/main/java/com/segment/analytics/kotlin/core/utilities/DateTimeUtils.kt

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,34 @@ package com.segment.analytics.kotlin.core.utilities
33
import java.text.SimpleDateFormat
44
import java.util.*
55

6-
/**
7-
* This function is a replacement for Instant.now().toString(). It produces strings in a
8-
* compatible format.
9-
*
10-
* Ex:
11-
* Instant.now(): 2023-04-19T04:03:46.880969Z
12-
* dateTimeNowString(): 2023-04-19T04:03:46.880Z
13-
*/
14-
fun dateTimeNowString(): String {
6+
object SegmentInstant {
7+
158
// Note, we should specify locale = Locale.ROOT, otherwise the timestamp returned will use
169
// the default locale, which may not be what we want.
17-
val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'Szzz", Locale.ROOT)
18-
val utc = TimeZone.getTimeZone("UTC");
19-
sdf.timeZone = utc;
20-
return sdf.format(Date()).replace("UTC", "Z")
10+
private val formatter: SimpleDateFormat =
11+
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.'SSSzzz", Locale.ROOT).apply {
12+
timeZone = TimeZone.getTimeZone("UTC")
13+
}
14+
15+
/**
16+
* This function is a replacement for Instant.now().toString(). It produces strings in a
17+
* compatible format.
18+
*
19+
* Ex:
20+
* Instant.now(): 2023-04-19T04:03:46.880969Z
21+
* dateTimeNowString(): 2023-04-19T04:03:46.880Z
22+
*/
23+
fun now(): String {
24+
return from(Date())
25+
}
26+
27+
internal fun from(date: Date): String {
28+
// internal use only. for testing purpose.
29+
return formatter.format(date).replace("UTC", "Z")
30+
}
2131
}
32+
33+
@Deprecated("Please use SegmentInstant.now() instead", ReplaceWith("SegmentInstant.now()"))
34+
fun dateTimeNowString(): String {
35+
return SegmentInstant.now()
36+
}

core/src/main/java/com/segment/analytics/kotlin/core/utilities/EventsFileManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ class EventsFileManager(
135135
// close events array and batch object
136136

137137

138-
val contents = """],"sentAt":"${dateTimeNowString()}","writeKey":"$writeKey"}"""
138+
val contents = """],"sentAt":"${SegmentInstant.now()}","writeKey":"$writeKey"}"""
139139
writeToFile(contents.toByteArray(), file)
140140
file.renameTo(File(directory, file.nameWithoutExtension))
141141
os?.close()

core/src/test/kotlin/com/segment/analytics/kotlin/core/AnalyticsTests.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.segment.analytics.kotlin.core.platform.DestinationPlugin
44
import com.segment.analytics.kotlin.core.platform.Plugin
55
import com.segment.analytics.kotlin.core.platform.plugins.ContextPlugin
66
import com.segment.analytics.kotlin.core.platform.plugins.SegmentDestination
7-
import com.segment.analytics.kotlin.core.utilities.dateTimeNowString
7+
import com.segment.analytics.kotlin.core.utilities.SegmentInstant
88
import com.segment.analytics.kotlin.core.utils.StubPlugin
99
import com.segment.analytics.kotlin.core.utils.TestRunPlugin
1010
import com.segment.analytics.kotlin.core.utils.clearPersistentStorage
@@ -28,7 +28,6 @@ import org.junit.jupiter.api.TestInstance
2828
import org.junit.jupiter.api.assertThrows
2929
import java.io.ByteArrayInputStream
3030
import java.net.HttpURLConnection
31-
import java.time.Instant
3231
import java.util.Date
3332
import java.util.UUID
3433

@@ -50,10 +49,8 @@ class AnalyticsTests {
5049
private val testScope = TestScope(testDispatcher)
5150

5251
init {
53-
mockkStatic(Instant::class)
54-
every { Instant.now() } returns Date(0).toInstant()
55-
mockkStatic(::dateTimeNowString)
56-
every { dateTimeNowString() } returns Date(0).toInstant().toString()
52+
mockkObject(SegmentInstant)
53+
every { SegmentInstant.now() } returns Date(0).toInstant().toString()
5754
mockkStatic(UUID::class)
5855
every { UUID.randomUUID().toString() } returns "qwerty-qwerty-123"
5956
}

core/src/test/kotlin/com/segment/analytics/kotlin/core/compat/JavaAnalyticsTest.kt

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import com.segment.analytics.kotlin.core.platform.DestinationPlugin
55
import com.segment.analytics.kotlin.core.platform.Plugin
66
import com.segment.analytics.kotlin.core.platform.plugins.ContextPlugin
77
import com.segment.analytics.kotlin.core.platform.plugins.SegmentDestination
8-
import com.segment.analytics.kotlin.core.utilities.dateTimeNowString
8+
import com.segment.analytics.kotlin.core.utilities.SegmentInstant
99
import com.segment.analytics.kotlin.core.utils.StubPlugin
1010
import com.segment.analytics.kotlin.core.utils.TestRunPlugin
1111
import com.segment.analytics.kotlin.core.utils.mockHTTPClient
@@ -21,7 +21,6 @@ import org.junit.jupiter.api.Assertions.*
2121
import org.junit.jupiter.api.BeforeEach
2222
import org.junit.jupiter.api.Nested
2323
import org.junit.jupiter.api.Test
24-
import java.time.Instant
2524
import java.util.*
2625
import java.util.function.Consumer
2726

@@ -43,10 +42,8 @@ internal class JavaAnalyticsTest {
4342
private val testScope = TestScope(testDispatcher)
4443

4544
init {
46-
mockkStatic(Instant::class)
47-
every { Instant.now() } returns Date(0).toInstant()
48-
mockkStatic(::dateTimeNowString)
49-
every { dateTimeNowString() } returns Date(0).toInstant().toString()
45+
mockkObject(SegmentInstant)
46+
every { SegmentInstant.now() } returns Date(0).toInstant().toString()
5047
mockkStatic(UUID::class)
5148
every { UUID.randomUUID().toString() } returns "qwerty-qwerty-123"
5249
mockHTTPClient()
Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
package com.segment.analytics.kotlin.core.utilities
22

3+
import io.mockk.every
4+
import io.mockk.mockkConstructor
5+
import io.mockk.mockkObject
6+
import org.junit.jupiter.api.Assertions.assertEquals
37
import org.junit.jupiter.api.Assertions.assertNotNull
48
import org.junit.jupiter.api.Test
59
import java.time.format.DateTimeFormatter.ISO_DATE_TIME
10+
import java.util.*
611

712
class DateTimeUtilsTest {
813

914
@Test
1015
fun `dateTimeNowString() produces a string in the correct ISO8601 format`() {
11-
val dateTimeNowString = dateTimeNowString()
16+
val dateTimeNowString = SegmentInstant.now()
1217
val date = ISO_DATE_TIME.parse(dateTimeNowString)
1318
assertNotNull(date)
1419
}
20+
21+
@Test
22+
fun `dateTimeNowString() returns three digit seconds`() {
23+
val date = Date(1700617928023L)
24+
val dateTimeNowString = SegmentInstant.from(date)
25+
assertEquals("2023-11-22T01:52:08.023Z", dateTimeNowString)
26+
}
1527
}

core/src/test/kotlin/com/segment/analytics/kotlin/core/utilities/EventsFileManagerTest.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.segment.analytics.kotlin.core.utilities
33
import com.segment.analytics.kotlin.core.TrackEvent
44
import com.segment.analytics.kotlin.core.emptyJsonObject
55
import io.mockk.every
6+
import io.mockk.mockkObject
67
import io.mockk.mockkStatic
78
import kotlinx.coroutines.test.runTest
89
import kotlinx.serialization.encodeToString
@@ -24,11 +25,8 @@ internal class EventsFileManagerTest{
2425
private val kvStore = PropertiesFile(directory.parentFile, "123")
2526

2627
init {
27-
mockkStatic(Instant::class)
28-
every { Instant.now() } returns Date(0).toInstant()
29-
30-
mockkStatic(::dateTimeNowString)
31-
every { dateTimeNowString() } returns Date(0).toInstant().toString()
28+
mockkObject(SegmentInstant)
29+
every { SegmentInstant.now() } returns Date(0).toInstant().toString()
3230
}
3331

3432
@BeforeEach

0 commit comments

Comments
 (0)