web-dev-qa-db-fra.com

Découvrez le nombre de jours du mois en R

J'ai un rendez-vous en P

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

Est-il possible de connaître le nombre de jours du mois de cette date? (En ce qui concerne les années bissextiles). Dans PHP, cela ressemblerait à ceci ( http://www.php.net/manual/en/function.date.php ):

days = format(date, "%t")

mais "% t" semble avoir une signification différente dans R. Existe-t-il une solution à ce problème?

26
R_User

Vous pouvez écrire une fonction simple pour le faire:

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

Invoquer comme:

> date = as.Date("2011-02-23", "%Y-%m-%d")
> numberOfDays(date)
[1] 28
> date # date is unchanged
[1] "2011-02-23"
20

La bibliothèque Hmisc a quelques fonctions utiles pour cela:

require(Hmisc)
monthDays(as.Date('2010-01-01'))
30
yoni

C’est aussi simple que de faire la différence entre deux dates - donc, faites-en le premier du mois et le mois suivant:

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> 

La as.numeric() la convertit en un nombre que vous pouvez utiliser. 

16

Le package "Lubridate" a requis la fonction "days_in_month" pour les années bissextiles.

Votre exemple:

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

Année bissextile (2016):

> date_leap = as.Date("2016-02-23", "%Y-%m-%d")
> days_in_month(date_leap)
Feb 
29 
15
Georgie Shimanovsky

Voici quelques approches. Les deux approches sont vectorisées, c’est-à-dire que l’entrée x peut être une seule date de classe "Date" ou un vecteur de telles dates.

1) Ceci convertit la date d'entrée, x, en un objet "yearmon", puis le reconvertit au dernier du mois et au premier du mois et soustrait les deux en ajoutant 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

ou pour un résultat numérique, utilisez:

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

1a) Une variation serait:

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

ou pour un résultat numérique:

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

2) Ceci est une solution de base. Nous définissons d’abord fom qui entre un vecteur "Date" et renvoie le premier du mois de chaque composant. Nous prenons maintenant la différence entre le premier du mois suivant et le premier du mois en cours.

fom <- function(x) as.Date(cut(x, "month"))
fom1 <- fom(x)
fom2 <- fom(fom1 +  32)
as.numeric(fom2 - fom1)
## [1] 30
12
G. Grothendieck

Voici un moyen simple: pour n dans 28:31, trouvez le plus grand nombre ayant pour résultat une date valide. Dans mes tests, cela est au moins 4 fois plus rapide que n'importe quelle méthode basée sur la différence de temps:

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

Comparaisons temporelles avec certaines des autres méthodes suggérées ici:

> 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 
7
Prasad Chalasani

Voici une autre fonction possible qui ne nécessite l'installation d'aucun paquet. Vous venez de nourrir la fonction un objet de date. Puisqu'il y a beaucoup d'autres excellentes réponses ici, je l'ai écrit avec le souci d'être assez simple et (espérons-le) facile à lire :)

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))
}
6
Jacob Amos

C'est l'approche de Dirk, mais elle est en fait placée dans une fonction, afin de vérifier si le mois prochain est également l'année suivante; et simplement soustraire les dates revient à utiliser 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)))
    }
}
2
joran

Je fournis un autre one-liner sans paquets supplémentaires nécessaires:

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

Vous devez fournir un objet Date à cette fonction avec le formatage de vos préférences.

2
Philip Khripkov

Vous pouvez passer l'année ou prendre l'année en cours par défaut:

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'))
}
2
Fernando

Salut, une autre façon d’obtenir les jours pourrait être:

# 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")
0
Rafa Barragan
> 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
0
정남재

Ceci est une autre solution alternative utilisant yearmon de Zoo. Ceci est un utilitaire rapide.

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

}

Vous pouvez décompresser get_day () pour en faire une ligne si vous le souhaitez.

0
Steve Lihn