106

I'm working with a csv which unfortunately has logged datetimes using the number format of 42705 although it should be 01/12/2016.

I'd like to convert it to the right format in R using lubridate or some other package. Is there a function that will handle it?

Waldi
  • 31,868
  • 6
  • 18
  • 66
elksie5000
  • 5,790
  • 9
  • 49
  • 75

5 Answers5

189

You don't need to use lubridate for this, the base function as.Date handles this type of conversion nicely. The trick is that you have to provide the origin, which in Excel is December 30, 1899.

as.Date(42705, origin = "1899-12-30")
# [1] "2016-12-01"

If you want to preserve your column types, you can try using the read_excel function from the readxl package. That lets you load an XLS or XLSX file with the number formatting preserved.

Andrew Brēza
  • 6,751
  • 3
  • 32
  • 39
  • 1
    Thank you for that. I'm still very new to R. It worked a treat. – elksie5000 Apr 05 '17 at 11:58
  • Quite welcome. I'm editing my response now since I realized the origin is slightly off. Give me a minute before you use this code in your project :-) – Andrew Brēza Apr 05 '17 at 11:59
  • Actually I just typed 01/12/2016 into Excel and converted it into a number. The value I got was 42381, not 42705. Using 42381 in the `as.Date` function gets you back to 1/12/2016. Are you sure that you copied the number correctly from Excel? – Andrew Brēza Apr 05 '17 at 12:01
  • Oh, I did exactly the same thing in my copy of Excel, but had a different number. Is because it's European day-month-year format? – elksie5000 Apr 05 '17 at 12:05
  • That's exactly what happened, I should have asked what date format you were using. It's still early here in the states and I'm obviously not thinking clearly yet. – Andrew Brēza Apr 05 '17 at 12:07
  • Hey, I just appreciated your swift response. Thank you. – elksie5000 Apr 05 '17 at 12:08
  • This is my favorite solution, but one caution mentioned in the documentation for the "as.Date" function is the handling of leap years can vary between programs, e.g. Excel intentionally misclassifies 1900 as a leap year. If your dates cover broad range, double check the conversion for the min and max dates in your range. – Robert Alan Greevy Jr PhD Apr 28 '20 at 14:31
  • 3
    In the French version of excel, the best solution is quite fascinating, for a date with hours: `as_datetime(Date,origin = "1969-12-31 24:00:00")` – Clément LVD May 31 '20 at 16:54
  • 2
    For those who wonder where the 1899-12-30 came from and if it is correct, it seems in some Excel versions Microsoft has used 1900 as the reference date and in some versions 1904! for this reason I suggest you to confirm the date from some other source as well. Source: https://support.microsoft.com/en-us/office/date-systems-in-excel-e7fe7167-48a9-4b96-bb53-5612a800b487 – Mehrad Mahmoudian Oct 08 '21 at 13:37
34

Here is another way to do it using janitor and tibble packages:

install.packages("janitor")
install.packages("tibble")

library(tibble)
library(janitor)

excel_numeric_to_date(as.numeric(as.character(YourDate)), date_system = "modern")    
Rui Barradas
  • 57,195
  • 8
  • 29
  • 57
Reza Rahimi
  • 489
  • 6
  • 6
  • convert_to_date() - also from the janitor package - can be used when there is a mix of Excel numeric dates and actual dates – userLL Aug 11 '21 at 05:17
17

openxlsx package also allows xls date conversion:

openxlsx::convertToDate(42705)
[1] "2016-12-01"

And as suggested by @Suren, convertToDateTime allows datetime conversion:

openxlsx::convertToDateTime(42705.5)
[1] "2016-12-01 12:00:00"
Waldi
  • 31,868
  • 6
  • 18
  • 66
2

As it was said, very good options:

as.Date(42705, origin = "1899-12-30")

openxlsx::convertToDate(42705)

Another way also could be:

format(as.Date(as.Date("1899-12-30") + 42705, "%d-%m-%Y"), "%d-%m-%Y")

Note you can change the output format where it's written %d-%m-%Y

(first of all, convert as.numeric if it's imported as character!,or converting in the formula:

format(as.Date(as.Date("1899-12-30") + as.numeric( number formatted as character), "%d-%m-%Y"), "%d-%m-%Y")
Martin Gal
  • 14,910
  • 4
  • 18
  • 37
2

If you work with the data.table package you could use as.IDate() for that:

require(data.table)

as.IDate(42705, origin = "1899-12-30")
# [1] "2016-12-01"

Works like base::as.Date() here.

andschar
  • 2,731
  • 1
  • 23
  • 32