-
Notifications
You must be signed in to change notification settings - Fork 2.1k
Fix timezone issues in scale_*_datetime #1767
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@hadley I think I've been able to fix the datetime scale with minimal implication for surrounding code - can you stress-test it? There are some points you may not like:
Example adapted from #1718 df <- data.frame(
time = as.POSIXct("2010-01-01", tz = "America/Chicago") + 1:10 * 3600,
y = 1:10
)
ggplot(df, aes(time, y)) + geom_point() + scale_x_datetime(date_labels = "%H:%M %Z") |
@@ -125,7 +125,10 @@ scale_datetime <- function(aesthetics, trans, | |||
minor_breaks <- date_breaks(date_minor_breaks) | |||
} | |||
if (!is.waive(date_labels)) { | |||
labels <- date_format(date_labels) | |||
labels <- function(self, x) { | |||
tz <- if (is.null(self$timezone)) "UTC" else self$timezone |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the default should be ""
, which means the default local timezone.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And can we add a tz parameter to the constructor to override the default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How should this behave if there is a mismatch between the timezone in the data and the one provided in the constructor? Should the constructor value only kick in if the data does not have a timezone provided?
self$timezone <- tz | ||
self$trans <- time_trans(self$timezone) | ||
} else { | ||
if (!identical(self$timezone, tz)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can drop this warning, as it's not very important.
I'll write up a few unit tests for you too |
These tests all look good to me: base_time <- function(tz = "") {
as.POSIXct(strptime("2015-06-01", "%Y-%m-%d", tz = tz))
}
df <- data.frame(
time1 = base_time("") + 0:6 * 3600,
time2 = base_time("UTC") + 0:6 * 3600,
time3 = base_time("Australia/Lord_Howe") + (0:6 + 13) * 3600, # has half hour offset
y = seq_along(x)
)
test_that("inherits timezone from data", {
# Local time
p <- ggplot(df, aes(y = y)) + geom_point(aes(time1))
sc <- layer_scales(p)$x
expect_equal(sc$timezone, NULL)
expect_equal(sc$get_labels()[1], "00:00")
# UTC
p <- ggplot(df, aes(y = y)) + geom_point(aes(time2))
sc <- layer_scales(p)$x
expect_equal(sc$timezone, "UTC")
expect_equal(sc$get_labels()[1], "00:00")
})
test_that("first timezone wins", {
p <- ggplot(df, aes(y = y)) +
geom_point(aes(time2)) +
geom_point(aes(time3), colour = "red") +
scale_x_datetime(date_breaks = "hour", date_labels = "%H:%M")
sc <- layer_scales(p)$x
expect_equal(sc$timezone, "UTC")
})
test_that("not cached across calls", {
scale_x <- scale_x_datetime(date_breaks = "hour", date_labels = "%H:%M")
p1 <- ggplot(df, aes(y = y)) + geom_point(aes(time2)) + scale_x
p2 <- ggplot(df, aes(y = y)) + geom_point(aes(time3)) + scale_x
expect_equal(layer_scales(p1)$x$timezone, "UTC")
expect_equal(layer_scales(p2)$x$timezone, "Australia/Lord_Howe")
}) |
LGTM |
And the timezone default stuff..? |
Oh my tests seem to suggest that it all works currently. I certainly couldn't figure out how to elicit the bug |
I was more referring to your wish for an argument in the constructor to set the timezone |
Oh, yeah, please do that! |
Should the argument be ignored in the presence of one encoded in the data? |
No, it should override the data. (i.e. it should default to NULL) |
So if data has one timezone and the scale has another it should first convert the data to the other timezone, or should the original timezone simply be ignored? |
There's no converting - the |
I see, that's easy then |
Looks good! |
This old issue has been automatically locked. If you believe you have found a related problem, please file a new issue (with reprex) and link to this issue. https://reprex.tidyverse.org/ |
Fixes #1718