【问题标题】:Converting from epochs using non-Gregorian calendars使用非公历从历元转换
【发布时间】:2017-05-26 02:32:41
【问题描述】:

我正在处理一堆气候模型输出(特别是CMIP5 models)。这些是带有时间戳的温度、风等的 netcdf。

它们都使用 UTC 中的 days since YYYY-mm-dd 00:00:00 约定。我一直在使用lubridate 转换为更简单的日期(不是日期时间)对象:

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

我遇到了两个问题。一是每个模型都有不同的时代。这很容易解决。另一个更棘手的问题是并非所有模型都使用公历。有些使用 365 天的变化,没有闰年。

我看不到在 lubridate 函数中指定非公历的任何方法。这可能吗?

【问题讨论】:

    标签: r date calendar lubridate tidyverse


    【解决方案1】:

    我在lubridate 中找不到这个功能,所以我写了一个函数来至少计算日期向量的每个元素与给定纪元之间的闰日数:

    # 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) 
    }
    

    有了这个,我可以通过添加缺少的闰日数将 365 天日历转换为公历:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-27
      • 1970-01-01
      • 2014-11-06
      • 1970-01-01
      • 2015-11-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多