Skip to content
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

force_tz() should convert dates to date-times #675

Closed
ClaytonJY opened this issue May 17, 2018 · 5 comments · Fixed by #825
Closed

force_tz() should convert dates to date-times #675

ClaytonJY opened this issue May 17, 2018 · 5 comments · Fixed by #825
Labels
bug wip

Comments

@ClaytonJY
Copy link

@ClaytonJY ClaytonJY commented May 17, 2018

Perhaps this is intentional, but it strikes me as unexpected:

library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following object is masked from 'package:base':
#> 
#>     date

tz(today())
#> [1] "UTC"

tz(force_tz(today(), "America/New_York"))
#> [1] "UTC"

tz(with_tz(today(), "America/New_York"))
#> [1] "America/New_York"

Latest Github version, 1.7.4.

In general, timezones for pure Dates seem to be discouraged in that virtually no lubridate functions will ever return a non-UTC date (e.g. today, as_date, date, etc.), but I can't find anything to this effect in the docs.

@vspinu
Copy link
Member

@vspinu vspinu commented Jun 1, 2018

I think the last two should return POSIX instead of date. I would qualify this as a bug.

Do you also find the first example unexpected? This is a new addition in the last minor version to avoid dealing explicitly with the NULL tzs, but I am not entirely convinced it was such a good idea.

@ClaytonJY
Copy link
Author

@ClaytonJY ClaytonJY commented Jun 2, 2018

I strongly recommend against up-converting dates to datetime in general, and I think doing so implicitly would be asking for trouble. The typical approach there is to assume the time is all-zeroes, but then with_tz can easily change the date which I suspect is rarely the desired outcome.

I hadn't thought of it when I created this issue, but on reflection, yes I think the first result is unexpected, given that I have a non-UTC locale set.

Would it make sense to drop timezones from time-free Dates altogether? e.g. tz would error or return NULL, with_tz/force_tz could warn or error, etc.

Potential problems might include edge cases like Samoa's missing day (https://zachholman.com/talk/utc-is-enough-for-everyone-right).

@vspinu
Copy link
Member

@vspinu vspinu commented Jun 2, 2018

You ask for an operation which makes sense on date-times, that implise that you are interpreting the date as an instant. Otherwise why would you do force_tz on a date?

Would it make sense to drop timezones from time-free Dates altogether?

Yes. I will revert it to NULL.

@ClaytonJY
Copy link
Author

@ClaytonJY ClaytonJY commented Jun 2, 2018

I agree force_tz doesn't make sense; I only tried it because I didn't get the expected behavior from with_tz. For consistency across a mix of dates and datetimes, my goal was to set the correct timezone, and tz(x) <- "America/New_York" leads to awkward code. After this discussion I don't even want to do that; I think we're in agreence that dates should not have timezones in any manner.

I'm happy to help with code, though I won't have time until at least tomorrow. Sounds like you want tz to return NULL; what about force_tz/with_tz? Erroring would make it clear lubridate doesn't support timezones on dates, but might also break users code. Could throw a warning in one release and an error in a subsequent release if breakage is a concern, but it's possible nobody else is trying to set timezones on their dates like I did.

@hadley
Copy link
Member

@hadley hadley commented Nov 19, 2019

It seems reasonable to me to return POSIXct when you explicit request a timezone be added to a Date. Adding a tzone attribute to a Date object is definitely wrong:

library(lubridate, warn.conflicts = FALSE)

tz(force_tz(today(), "America/New_York"))
#> [1] "UTC"
class(force_tz(today(), "America/New_York"))
#> [1] "Date"

tz(with_tz(today(), "America/New_York"))
#> [1] "America/New_York"
class(with_tz(today(), "America/New_York"))
#> [1] "Date"

tz(`tz<-`(today(), "America/New_York"))
#> [1] "UTC"
class(`tz<-`(today(), "America/New_York"))
#> [1] "Date"

Created on 2019-11-20 by the reprex package (v0.3.0)

(I agree that lubridate seems to upclass dates to date-times too readily; but that's a separate issue)

@hadley hadley changed the title force_tz doesn't work on pure Dates force_tz() should convert dates to date-times Nov 19, 2019
@hadley hadley added the bug label Nov 19, 2019
@hadley hadley added the wip label Nov 20, 2019
netbsd-srcmastr pushed a commit to NetBSD/pkgsrc that referenced this issue May 30, 2021
Version 1.7.10
==============

### NEW FEATURES

* `fast_strptime()` and `parse_date_time2()` now accept multiple formats and apply them in turn

### BUG FIXES

* [#926](tidyverse/lubridate#926) Fix incorrect division of intervals by months involving leap years
* Fix incorrect skipping of digits during parsing of the `%z` format

Version 1.7.9.2
===============

### NEW FEATURES

* [#914](tidyverse/lubridate#914) New `rollforward()` function
* [#928](tidyverse/lubridate#928) On startup lubridate now resets TZDIR to a proper directory when it is set to non-dir values like "internal" or "macOS" (a change introduced in R4.0.2)
* [#630](tidyverse/lubridate#630) New parsing functions `ym()` and `my()`

### BUG FIXES

* [#930](tidyverse/lubridate#930) `as.period()` on intervals now returns valid Periods with double fields (not integers)



Version 1.7.9
=============

### NEW FEATURES

* [#871](tidyverse/lubridate#893) Add `vctrs` support


### BUG FIXES

* [#890](tidyverse/lubridate#890) Correctly compute year in `quarter(..., with_year = TRUE)`
* [#893](tidyverse/lubridate#893) Fix incorrect parsing of abbreviated months in locales with trailing dot (regression in v1.7.8)
* [#886](tidyverse/lubridate#886) Fix `with_tz()` for POSIXlt objects
* [#887](tidyverse/lubridate#887) Error on invalid numeric input to `month()`
* [#889](tidyverse/lubridate#889) Export new dmonth function

Version 1.7.8
=============

### NEW FEATURES

* (breaking) Year and month durations now assume 365.25 days in a year consistently in conversion and constructors. Particularly `dyears(1) == years(1)` is now `TRUE`.
* Format and print methods for 0-length objects are more consistent.
* New duration constructor `dmonths()` to complement other duration constructors.
*
* `duration()` constructor now accepts `months` and `years` arguments.
* [#629](tidyverse/lubridate#629) Added `format_ISO8601()` methods.
* [#672](tidyverse/lubridate#672) Eliminate all partial argument matches
* [#674](tidyverse/lubridate#674) `as_date()` now ignores the `tz` argument
* [#675](tidyverse/lubridate#675) `force_tz()`, `with_tz()`, `tz<-` convert dates to date-times
* [#681](tidyverse/lubridate#681) New constants `NA_Date_` and `NA_POSIXct_` which parallel built-in primitive constants.
* [#681](tidyverse/lubridate#681) New constructors `Date()` and `POSIXct()` which parallel built-in primitive constructors.
* [#695](tidyverse/lubridate#695) Durations can now be compared with numeric vectors.
* [#707](tidyverse/lubridate#707) Constructors return 0-length inputs when called with no arguments
* [#713](tidyverse/lubridate#713) (breaking) `as_datetime()` always returns a `POSIXct()`
* [#717](tidyverse/lubridate#717) Common generics are now defined in `generics` dependency package.
* [#719](tidyverse/lubridate#719) Negative Durations are now displayed with leading `-`.
* [#829](tidyverse/lubridate#829) `%within%` throws more meaningful messages when applied on unsupported classes
* [#831](tidyverse/lubridate#831) Changing hour, minute or second of Date object now yields POSIXct.
* [#869](tidyverse/lubridate#869) Propagate NAs to all internal components of a Period object

### BUG FIXES

* [#682](tidyverse/lubridate#682) Fix quarter extraction with small `fiscal_start`s.
* [#703](tidyverse/lubridate#703) `leap_year()` works with objects supported by `year()`.
* [#778](tidyverse/lubridate#778) `duration()/period()/make_difftime()` work with repeated units
* `c.Period` concatenation doesn't fail with empty components.
* Honor `exact = TRUE` argument in `parse_date_time2`, which was so far ignored.

Version 1.7.4
=============

### NEW FEATURES

* [#658](tidyverse/lubridate#658) `%within%` now accepts a list of intervals, in which case an instant is checked if it occurs within any of the supplied intervals.

### CHANGES

* [#661](tidyverse/lubridate#661) Throw error on invalid multi-unit rounding.
* [#633](tidyverse/lubridate#633) `%%` on intervals relies on `%m+` arithmetic and doesn't produce NAs when intermediate computations result in non-existent dates.
* `tz()` always returns "UTC" when `tzone` attribute cannot be inferred.

### BUG FIXES

* [#664](tidyverse/lubridate#664) Fix lookup of period functions in `as.period`
* [#649](tidyverse/lubridate#664) Fix system timezone memoization

Version 1.7.3
=============

### BUG FIXES

* [#643](tidyverse/lubridate#643), [#640](tidyverse/lubridate#640), [#645](tidyverse/lubridate#645) Fix faulty caching of system timezone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug wip
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants