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

Use the exported clock API instead of localtime.c #322

Merged
merged 18 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ Authors@R:
person(given = "https://github.com/mandreyel/",
role = "cph",
comment = "mio library"),
person(given = "R Core Team",
role = "ctb",
comment = "localtime.c code adapted from R"),
person(given = "Jukka",
family = "Jylänki",
role = "cph",
Expand All @@ -42,6 +39,7 @@ Imports:
bit64,
crayon,
cli,
clock (>= 0.2.0),
glue,
hms,
lifecycle,
Expand Down Expand Up @@ -73,6 +71,7 @@ Suggests:
waldo,
xml2
LinkingTo:
clock (>= 0.2.0),
progress (>= 1.2.1),
cpp11 (>= 0.2.0)
VignetteBuilder:
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# vroom (development version)

* vroom now uses the clock package when parsing date-times (#273).

* `vroom_write_lines()` now works as intended (#291).

* New `vroom(show_col_specs=)` argument to more simply control showing of column specifications after parsing.
Expand Down
18 changes: 12 additions & 6 deletions R/locale.R
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ locale <- function(date_names = "en",
stop("`decimal_mark` and `grouping_mark` must be different", call. = FALSE)
}

check_tz(tz)
tz <- check_tz(tz)
check_encoding(encoding)

structure(
Expand Down Expand Up @@ -102,13 +102,19 @@ default_locale <- function() {
check_tz <- function(x) {
stopifnot(is.character(x), length(x) == 1)

if (identical(x, ""))
return(TRUE)
if (identical(x, "")) {
x <- Sys.timezone()

if (x %in% OlsonNames())
return(TRUE)
if (identical(x, "") || identical(x, NA_character_)) {
x <- "UTC"
}
}

stop("Unknown TZ ", x, call. = FALSE)
if (x %in% clock::zone_database_names()) {
x
} else {
stop("Unknown TZ ", x, call. = FALSE)
}
}
check_encoding <- function(x) {
stopifnot(is.character(x), length(x) == 1)
Expand Down
3 changes: 3 additions & 0 deletions R/zzz.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
}

.onLoad <- function(...) {
# Ensure clock callables are loaded
requireNamespace("clock", quietly = TRUE)

# only register conflicting S3 methods if readr is not already loaded.
if (!"readr" %in% loadedNamespaces()) {
s3_register("base::format", "col_spec")
Expand Down
45 changes: 0 additions & 45 deletions inst/COPYRIGHTS
Original file line number Diff line number Diff line change
Expand Up @@ -63,48 +63,3 @@ grisu3 is licensed for use as follows
*/

====

localtime.c is licensed for use as follows

/*
* R : A Computer Language for Statistical Data Analysis
* Modifications copyright (C) 2007-2015 The R Core Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, a copy is available at
* https://www.R-project.org/Licenses/
*/


/*
The orginal version of this file stated

** This file is in the public domain, so clarified as of
** 1996-06-05 by Arthur David Olson.

The modified version is copyrighted. Modifications include:
setting EOVERFLOW
where to find the zi database
Mingw-w64 changes
removing ATTRIBUTE_PURE, conditional parts for e.g. ALL_STATE
use of 'unknown' isdst
use of 64-bit time_t irrespective of platform.
use of tm_zone and tm_gmtoff on all platforms.

Additional modifications made by Hadley Wickham, (c) RStudio:
* provide tzset_name() to avoid use of env vars
* eliminate code unrelated to mktime

*/

====
1 change: 0 additions & 1 deletion inst/WORDLIST
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ KiB
knitr
lbzip
Lifecycle
localtime
mandreyel
mio
mtcars
Expand Down
1 change: 0 additions & 1 deletion man/vroom-package.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

116 changes: 27 additions & 89 deletions src/DateTime.h
Original file line number Diff line number Diff line change
@@ -1,55 +1,11 @@
#ifndef READR_DATE_TIME_H_
#define READR_DATE_TIME_H_

#include "localtime.h"
#include <cpp11/R.hpp>
#include <ctime>
#include <clock/clock.h>
#include <stdlib.h>
#include <string>

// Much of this code is adapted from R's src/main/datetime.c.
// Author: The R Core Team.
// License: GPL >= 2

static const int month_length[12] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static const int month_start[12] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};

// Leap days occur in a 400 year cycle: this records the cumulative number
// of leap days in per cycle. Generated with:
// is_leap <- function(y) (y %% 4) == 0 & ((y %% 100) != 0 | (y %% 400) == 0)
// cumsum(is_leap(0:399))
static const int leap_days[400] = {
0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5,
5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10,
10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
15, 15, 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19,
19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24,
24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, 28,
28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32, 32, 32,
33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, 36, 36, 36, 36, 37, 37, 37,
37, 38, 38, 38, 38, 39, 39, 39, 39, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42,
42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47,
47, 47, 47, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50,
51, 51, 51, 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55,
55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60,
60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64, 64, 64, 65,
65, 65, 65, 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 72, 73, 73, 73, 73, 73, 73, 73,
73, 74, 74, 74, 74, 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78,
78, 78, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82, 82, 82, 82, 83,
83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85, 86, 86, 86, 86, 87, 87, 87, 87,
88, 88, 88, 88, 89, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92,
92, 93, 93, 93, 93, 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97,
97};

static const int cycle_days = 400 * 365 + 97;

inline int is_leap(unsigned y) {
return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0);
}

class DateTime {
int year_, mon_, day_, hour_, min_, sec_, offset_;
double psec_;
Expand All @@ -64,7 +20,7 @@ class DateTime {
int min = 0,
int sec = 0,
double psec = 0,
const std::string& tz = "")
const std::string& tz = "UTC")
: year_(year),
mon_(mon),
day_(day),
Expand All @@ -83,14 +39,11 @@ class DateTime {
bool validDateTime() const { return validDate() && validTime(); }

bool validDate() const {
// vroom does not allow negative years, date does
if (year_ < 0)
return false;
if (mon_ < 0 || mon_ > 11)
return false;
if (day_ < 0 || day_ >= days_in_month())
return false;

return true;
return (date::year{year_} / mon_ / day_).ok();
}

bool validTime() const {
Expand Down Expand Up @@ -122,52 +75,37 @@ class DateTime {
if (!validDate())
return NA_REAL;

// Number of days since start of year
int day = month_start[mon_] + day_;
if (mon_ > 1 && is_leap(year_))
day++;

// Number of days since 0000-01-01
// Leap years come in 400 year cycles so determine which cycle we're
// in, and what position we're in within that cycle.
int ly_cycle = year_ / 400;
int ly_offset = year_ - (ly_cycle * 400);
if (ly_offset < 0) {
ly_offset += 400;
ly_cycle--;
}
day += ly_cycle * cycle_days + ly_offset * 365 + leap_days[ly_offset];

// Convert to number of days since 1970-01-01
day -= 719528;

return day;
const date::year_month_day ymd{date::year(year_) / mon_ / day_};
const date::sys_days st{ymd};
return st.time_since_epoch().count();
}

double localtime() const {
if (!validDateTime())
return NA_REAL;

struct Rtm tm;
tm.tm_year = year_ - 1900;
tm.tm_mon = mon_;
tm.tm_mday = day_ + 1;
tm.tm_hour = hour_;
tm.tm_min = min_;
tm.tm_sec = sec_;
// The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight
// Saving Time is in effect, zero if Daylight Saving Time is not in effect,
// and less than zero if the information is not available.
tm.tm_isdst = -1;

time_t time = my_mktime(&tm, tz_.c_str());
return time + psec_ + offset_;
}
const date::time_zone* p_time_zone = rclock::locate_zone(tz_);

const date::local_seconds lt =
std::chrono::seconds{sec_} +
std::chrono::minutes{min_} +
std::chrono::hours{hour_} +
date::local_days{date::year{year_} / mon_ / day_};

const date::local_info info = rclock::get_local_info(lt, p_time_zone);

switch (info.result) {
case date::local_info::unique:
return (lt.time_since_epoch() - info.first.offset).count() + psec_ + offset_;
case date::local_info::ambiguous:
// Choose `earliest` of the two ambiguous times
return (lt.time_since_epoch() - info.first.offset).count() + psec_ + offset_;
case date::local_info::nonexistent:
return NA_REAL;
}

inline int days_in_month() const {
return month_length[mon_] + (mon_ == 1 && is_leap(year_));
throw std::runtime_error("should never happen");
}
inline int days_in_year() const { return 365 + is_leap(year_); }
};

#endif
Loading