2017-05-26 2 views
0

Je travaille avec un groupe de modèles climatiques (CMIP5 models, en particulier). Ce sont les valeurs netcdfs de la température horodatée, du vent, etc.Conversion d'époques à l'aide de calendriers non-grégoriens

Ils utilisent tous une convention days since YYYY-mm-dd 00:00:00 en UTC. J'ai la conversion à ce jour plus facile (pas de date-heure) en utilisant des objets lubridate:

library(tidyverse) 
input$date.utc = 
    ymd_hms('0001-01-01 00:00:00', tz = 'UTC') + 
    days(floor(input$time)) 

J'ai frappé deux problèmes. L'un est que chaque modèle a une époque différente. C'est assez facile à réparer. L'autre problème, plus difficile, est que tous les modèles n'utilisent pas un calendrier grégorien. Certains utilisent une variation de 365 jours, où il n'y a pas d'années bissextiles.

Je ne vois aucun moyen de spécifier un calendrier non-grégorien dans les fonctions lubridate. Est-ce possible?

Répondre

0

Je ne pouvais pas trouver cette fonctionnalité dans lubridate, j'ai donc écrit une fonction pour calculer au moins le nombre de jours bissextiles entre chaque élément d'un vecteur de dates et une époque donnée:

# count_leap_days: returns an integer for the number of leap days between a 
# supplied vector of dates and a fixed epoch 
count_leap_days <- function(dates, epoch = ymd('1850-01-01'), proleptic = FALSE) 
{ 
    require(lubridate) 

    # check input 
    if (!is(epoch, 'Date') | !is(dates, 'Date')) 
    { 
    stop('count_leap_days: both arguments must be Date objects.') 
    } 
    if (any(dates <= epoch)) 
    { 
    stop('count_leap_days: dates should all be later than epoch.') 
    } 
    if (proleptic = FALSE & epoch < ymd('1582-10-15')) 
    { 
    message('count_leap_days: ', 
     'no leap days before 1582-10-15 unless proleptic = TRUE.') 
    epoch = ymd('1582-10-15') 
    } 

    # get the year range 
    # exclude start (end) years if they begin after (start before) feb 29 
    y.epoch = year(epoch) + 
    ifelse(epoch >= ymd(paste0(year(epoch), '-03-01')), 1, 0) 
    y.dates = year(dates) - 
    ifelse(dates <= ymd(paste0(year(dates), '-02-28')), 1, 0) 
    span = y.dates - y.epoch + 1 

    # a year is a leap year if it's: 
    # - divisble by 4. but 
    # - NOT if it's also divisible by 100, unless 
    # - it's also divisible by 400. 
    # all years div. by 4 are also div. by 100, and 
    # all years div. by 100 are also div. by 400. 
    # hence, total days = (div. by 4) - (div. by 100) + (div. by 400) 
    div4 = span %/% 4 + 
    ifelse(
     (y.epoch %% 4) %in% c(0, (4 - (span %% 4) - 1):(4 - 1)) & 
     (y.dates %% 4) %in% 0:(span %% 4 - 1), 
    1, 0) 
    div100 = span %/% 100 + 
    ifelse(
     (y.epoch %% 100) %in% c(0, (100 - (span %% 100) - 1):(100 - 1)) & 
     (y.dates %% 100) %in% 0:(span %% 100 - 1), 
    1, 0) 
    div400 = span %/% 400 + 
    ifelse(
     (y.epoch %% 400) %in% c(0, (400 - (span %% 400) - 1):(400 - 1)) & 
     (y.dates %% 400) %in% 0:(span %% 400 - 1), 
    1, 0) 
    return(div4 - div100 + div400) 
} 

Avec cette , Je peux convertir d'un calendrier de 365 jours en grégorien en ajoutant simplement le nombre de jours bissextiles manquants:

input$date.utc = input$date.utc + 
    count_leap_days(input$date.utc, epoch = epoch)