Skip to content

Commit

Permalink
[SPARK-11752] [SQL] fix timezone problem for DateTimeUtils.getSeconds
Browse files Browse the repository at this point in the history
code snippet to reproduce it:
```
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"))
val t = Timestamp.valueOf("1900-06-11 12:14:50.789")
val us = fromJavaTimestamp(t)
assert(getSeconds(us) === t.getSeconds)
```

it will be good to add a regression test for it, but the reproducing code need to change the default timezone, and even we change it back, the `lazy val defaultTimeZone` in `DataTimeUtils` is fixed.

Author: Wenchen Fan <[email protected]>

Closes apache#9728 from cloud-fan/seconds.
  • Loading branch information
cloud-fan authored and davies committed Nov 16, 2015
1 parent 0e79604 commit 06f1fdb
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -395,33 +395,35 @@ object DateTimeUtils {
/**
* Returns the microseconds since year zero (-17999) from microseconds since epoch.
*/
def absoluteMicroSecond(microsec: SQLTimestamp): SQLTimestamp = {
private def absoluteMicroSecond(microsec: SQLTimestamp): SQLTimestamp = {
microsec + toYearZero * MICROS_PER_DAY
}

private def localTimestamp(microsec: SQLTimestamp): SQLTimestamp = {
absoluteMicroSecond(microsec) + defaultTimeZone.getOffset(microsec / 1000) * 1000L
}

/**
* Returns the hour value of a given timestamp value. The timestamp is expressed in microseconds.
*/
def getHours(microsec: SQLTimestamp): Int = {
val localTs = absoluteMicroSecond(microsec) + defaultTimeZone.getOffset(microsec / 1000) * 1000L
((localTs / MICROS_PER_SECOND / 3600) % 24).toInt
((localTimestamp(microsec) / MICROS_PER_SECOND / 3600) % 24).toInt
}

/**
* Returns the minute value of a given timestamp value. The timestamp is expressed in
* microseconds.
*/
def getMinutes(microsec: SQLTimestamp): Int = {
val localTs = absoluteMicroSecond(microsec) + defaultTimeZone.getOffset(microsec / 1000) * 1000L
((localTs / MICROS_PER_SECOND / 60) % 60).toInt
((localTimestamp(microsec) / MICROS_PER_SECOND / 60) % 60).toInt
}

/**
* Returns the second value of a given timestamp value. The timestamp is expressed in
* microseconds.
*/
def getSeconds(microsec: SQLTimestamp): Int = {
((absoluteMicroSecond(microsec) / MICROS_PER_SECOND) % 60).toInt
((localTimestamp(microsec) / MICROS_PER_SECOND) % 60).toInt
}

private[this] def isLeapYear(year: Int): Boolean = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class DateTimeUtilsSuite extends SparkFunSuite {
assert(getSeconds(c.getTimeInMillis * 1000) === 9)
}

test("hours / miniute / seconds") {
test("hours / minutes / seconds") {
Seq(Timestamp.valueOf("2015-06-11 10:12:35.789"),
Timestamp.valueOf("2015-06-11 20:13:40.789"),
Timestamp.valueOf("1900-06-11 12:14:50.789"),
Expand Down

0 comments on commit 06f1fdb

Please sign in to comment.