Узнайте количество дней месяца в R

r date

23371 просмотра

15 ответа

У меня свидание в П

 date = as.Date("2011-02-23", "%Y-%m-%d")

Можно ли узнать количество дней в месяце этой конкретной даты? (По отношению к високосным годам). В PHP это будет выглядеть примерно так ( http://www.php.net/manual/en/function.date.php ):

days = format(date, "%t")

но "% t", кажется, имеет другое значение в R. Есть ли решение этой проблемы?

Автор: R_User Источник Размещён: 17.05.2019 03:08

Ответы (15)


20 плюса

Решение

Вы можете написать простую функцию для этого:

numberOfDays <- function(date) {
    m <- format(date, format="%m")

    while (format(date, format="%m") == m) {
        date <- date + 1
    }

    return(as.integer(format(date - 1, format="%d")))
}

Вызывать как:

> date = as.Date("2011-02-23", "%Y-%m-%d")
> numberOfDays(date)
[1] 28
> date # date is unchanged
[1] "2011-02-23"
Автор: Grzegorz Szpetkowski Размещён: 05.06.2011 01:45

30 плюса

Библиотека Hmisc имеет несколько полезных функций для этого:

require(Hmisc)
monthDays(as.Date('2010-01-01'))
Автор: yoni Размещён: 26.09.2011 03:53

16 плюса

Это так же просто, как принять разницу между двумя датами, поэтому сделайте это первым месяцем и следующим месяцем:

R> difftime( as.Date("2011-06-01"), as.Date("2011-05-01") )
Time difference of 31 days
R> as.numeric(difftime( as.Date("2011-06-01"), as.Date("2011-05-01") ))
[1] 31
R> 

as.numeric()Слепки это номер , который вы можете использовать.

Автор: Dirk Eddelbuettel Размещён: 05.06.2011 01:56

15 плюса

Пакет "Lubridate" имеет обязательную функцию days_in_month по отношению к високосным годам.

Ваш пример:

> date = as.Date("2011-02-23", "%Y-%m-%d")
> days_in_month(date)
Feb
28

Високосный год (2016):

> date_leap = as.Date("2016-02-23", "%Y-%m-%d")
> days_in_month(date_leap)
Feb 
29 
Автор: Georgie Shimanovsky Размещён: 04.02.2017 08:56

12 плюса

Вот пара подходов. Оба подхода векторизованы, т. Е. Входными данными xможет быть одна "Date"дата класса или вектор таких дат.

1) Это преобразует введенную дату xв "yearmon"объект, а затем преобразует ее обратно в конец месяца и первое число месяца и вычитает два, добавляя 1.

x <- Sys.Date() # use today as the test date

library(zoo)
ym <- as.yearmon(x)
as.Date(ym, frac = 1) - as.Date(ym) + 1
## Time difference of 30 days

или для числового результата используйте:

as.numeric(as.Date(ym, frac = 1) - as.Date(ym) + 1)
## [1] 30

1a) Вариант будет:

as.Date(ym + 1/12) - as.Date(ym)
## Time difference of 30 days

или для числового результата:

as.numeric(as.Date(ym + 1/12) - as.Date(ym))
## [1] 30

2) Это базовое решение. Сначала мы определяем, fomкакой вводит "Date"вектор и возвращает первое число месяца каждого компонента. Теперь мы просто берем разницу между первым из следующего месяца и первым из текущего месяца.

fom <- function(x) as.Date(cut(x, "month"))
fom1 <- fom(x)
fom2 <- fom(fom1 +  32)
as.numeric(fom2 - fom1)
## [1] 30
Автор: G. Grothendieck Размещён: 05.06.2011 05:16

7 плюса

Вот простой способ: для nв 28:31, найти наибольшее количество , которое приводит к действительной дате. В моих тестах это по крайней мере в 4 раза быстрее, чем любой из методов, основанных на разнице во времени:

ndays <- function(d) {
  last_days <- 28:31
  rev(last_days[which(!is.na( 
                             as.Date( paste( substr(d, 1, 8), 
                                             last_days, sep = ''), 
                                      '%Y-%m-%d')))])[1]
}

> ndays('1999-03-10')
[1] 31
> ndays('1999-04-10')
[1] 30
> ndays('2000-02-10')
[1] 29

Сроки сравнения с некоторыми из других методов, предлагаемых здесь:

> system.time( replicate( 5000, 
                          nd <- { 
   ym <- as.yearmon('2011-06-01'); 
   as.numeric( as.Date(ym, frac = 1) - as.Date(ym) + 1)
   }))

   user  system elapsed 
 16.634   1.807  18.238 

> system.time( replicate( 5000, 
               nd <- as.numeric( difftime( as.Date("2011-06-01"), 
                                           as.Date("2011-05-01") ))))
   user  system elapsed 
  3.137   0.341   3.470 

> system.time( replicate( 5000, nd <- ndays('2011-06-01')))
   user  system elapsed 
  0.729   0.044   0.771 
Автор: Prasad Chalasani Размещён: 05.06.2011 05:49

6 плюса

Вот еще одна возможная функция, которая не требует установки каких-либо пакетов. Вы просто кормите функцию объектом даты. Так как здесь есть много других отличных ответов, я написал их, чтобы быть довольно простым и (надеюсь) простым для чтения :)

daysInMonth <- function(d = Sys.Date()){

  m = substr((as.character(d)), 6, 7)              # month number as string
  y = as.numeric(substr((as.character(d)), 1, 4))  # year number as numeric

  # Quick check for leap year
  leap = 0
  if ((y %% 4 == 0 & y %% 100 != 0) | y %% 400 == 0)
    leap = 1

  # Return the number of days in the month
  return(switch(m,
                '01' = 31,
                '02' = 28 + leap,  # adds 1 if leap year
                '03' = 31,
                '04' = 30,
                '05' = 31,
                '06' = 30,
                '07' = 31,
                '08' = 31,
                '09' = 30,
                '10' = 31,
                '11' = 30,
                '12' = 31))
}
Автор: Jacob Amos Размещён: 29.07.2014 05:12

2 плюса

Это в основном подход Дирка, но на самом деле он помещен в функцию, чтобы проверить, когда следующий месяц также будет в следующем году; и просто вычитание даты аналогично использованию difftime():

numberOfDays <- function(d){
    temp <- unlist(strsplit(as.character(d),"-"))
    begin <- as.Date(paste(temp[1],temp[2],"01",sep="-"))
    if (temp[2] != "12"){
        nextMonth <- as.character(as.integer(temp[2])+1)
        end <- as.Date(paste(temp[1],nextMonth,"01",sep="-"))
        return(as.integer(as.Date(end) - as.Date(begin)))
    } 
    else{
        nextYear <- as.character(as.integer(temp[1])+1)
        end <- as.Date(paste(nextYear,"01","01",sep="-"))
        return(as.integer(as.Date(end) - as.Date(begin)))
    }
}
Автор: joran Размещён: 05.06.2011 02:09

2 плюса

Вы можете передать год или взять текущий год по умолчанию:

days.in.month = function(month, year = NULL){

  month = as.integer(month)

  if (is.null(year))
    year = as.numeric(format(Sys.Date(), '%Y'))

  dt = as.Date(paste(year, month, '01', sep = '-'))
  dates = seq(dt, by = 'month', length = 2)
  as.numeric(difftime(dates[2], dates[1], units = 'days'))
}
Автор: Fernando Размещён: 16.09.2013 06:49

2 плюса

Я предоставляю еще один вкладыш, никаких дополнительных пакетов не требуется:

NumberOfDays <- function(date) 
return(as.numeric(format(as.Date(paste0(format(date,format="%Y"),formatC(ifelse(format(date,format="%m")=="12",0,as.numeric(format(date,format="%m")))+1,width=2,format="d",flag="0"),"01"),"%Y%m%d")-1,format="%d")))

> NumberOfDays(as.Date("2015-02-14","%Y-%m-%d"))
[1] 28

> system.time(NumberOfDays(as.Date("2015-02-14","%Y-%m-%d")))
    user       system      elapsed
0.0010000000 0.0000000000 0.0009999999

Вы должны предоставить объект Date этой функции с форматированием по своему усмотрению.

Автор: Philip Khripkov Размещён: 14.06.2015 04:46

0 плюса

Привет еще один способ получить дни может быть:

# Any date
Today <- Sys.Date()
# Get Month and Year
Month <- format(Today,"%m")
Year <- format(Today,"%Y")
# get first date for the next month and then subtract 1
Days <- format(
            as.Date( 
                paste0("01/",(as.numeric(Month)%%12)+1,"/",Year)
                ,"%d/%m/%Y")-1,"%d")
Автор: Rafa Barragan Размещён: 22.09.2016 11:29

0 плюса

> Ymd<-"201602"
> lastDate<-format(seq(as.POSIXct(sprintf("%s%s",substr(Ymd,1,6),"01"),format="%Y%m%d"),length=2,by="1 month")-1,"%Y%m%d")[2]
> cat(as.integer(lastDate)%%100)
29
# Other Output
> lastDate
[1] "20160229"
> cat(substr(lastDate,7,8))
29
Автор: 정남재 Размещён: 01.02.2018 01:20

0 плюса

Это еще одно альтернативное решение с использованием зоопарка yearmon. Это быстрая утилита.

require(zoo)
days_in_month <- function(d) {
    rigor_days_in_month <- function(d) {
        get_day <- function(x) as.numeric(format(x,"%d"))
        m <- zoo::as.yearmon(d)
        get_day(as.Date(m, frac = 1))
    }
    mm <- as.numeric(format(d,"%m")) # get_month
    ifelse(mm %in% c(1,3,5,7,8,10,12), 31,
        ifelse(mm != 2, 30, 
           rigor_days_in_month(d)))

}

Вы можете развернуть get_day (), чтобы превратить его в однострочник, если хотите.

Автор: Steve Lihn Размещён: 17.02.2018 08:49

0 плюса

Да!

Вам просто нужно использовать функцию days_in_month()из lubridateпакета. Следуйте краткому примеру, как вы можете использовать функцию, чтобы указать дни месяца.

lubridate::days_in_month(as.Date("2018-02-01"))

Выход:

28 февраля

Для получения дополнительной информации о функции: нажмите здесь

Автор: Arthur Vaz Размещён: 12.02.2019 12:46

-1 плюса

Я опаздываю на вечеринку, но эта функция намного лучше и поддерживает векторы:

month_days <- function(mon) {
  # input as class "Date"
  require(lubridate)
  day(mon) <- 1
  given <- mon
  month(given) <- month(given) + 1
  as.numeric(given - mon)
}
Автор: Zafar Размещён: 16.09.2017 01:21
Вопросы из категории :
32x32