Since 1196
should give the millis for 2022-04-11
, it seems like you want to exclude leap days altogether. Is this the case?
If you include leap days, it's quite simple:
function toMillis(day) {
var dayOffset = ee.Date('2019-01-01')
.difference(ee.Date('1970-01-01'), 'days')
.subtract(1)
return day.add(dayOffset)
.multiply(1000) // Second to millis
.multiply(3600) // Hour to second
.multiply(24) // Day to hour
}
Otherwise, it's tricky. Since you need to do date manipulations on an image, you cannot rely on ee.Date
, so you have to manually deal with the date logic, which is notoriously easy to get wrong. Anyway, below is my stab at implementing something like this. I'm sure there are problems with the implementation, it certainly it has some assumptions that causes this to fail if your date is too far in the future (2070s).
function toMillis(day) {
var referenceYear = ee.Number(2019)
// Could be different due to leap years.
var approximateYear = day.subtract(1).divide(365).floor().add(referenceYear)
var leapYears = ee.Image(ee.Array( // Array image with leap years
ee.List.sequence(referenceYear, 2070)
.map(function isLeapYear(year) {
year = ee.Number(year)
return ee.Date.fromYMD(year.add(1), 1, 1).advance(-1, 'day') // Last of year
.getRelative('day', 'year').gt(364) // Got the extra day
.multiply(year) // Return the actual year if a leap year or 0
})
.filter(ee.Filter.neq('item', 0))
))
var numberOfLeapYears = leapYears
.arrayMask(leapYears.lte(approximateYear)) // Mask out leap years after the year of the pixel
.arrayLength(0) // Results in an image where the pixel value represents the number of leap years
var leapYearAdjustedDay = day.add(numberOfLeapYears)
var year = leapYearAdjustedDay.subtract(1).divide(365).floor().add(referenceYear)
var isLeapYear = leapYears.arrayMask(leapYears.eq(year))
.arrayLength(0)
var januaryFirstDay = year.subtract(referenceYear).multiply(365).add(numberOfLeapYears).add(1).subtract(isLeapYear)
var dayOfYear = leapYearAdjustedDay.subtract(januaryFirstDay).add(1)
var isBeforeLeapDay = dayOfYear.lte(31 + 29)
var timeOfYearAdjustment = isLeapYear.and(isBeforeLeapDay) // 1 if before leap day on leap year, otherwise 0
var finalDay = leapYearAdjustedDay
.subtract(timeOfYearAdjustment)
var dayOffset = ee.Date.fromYMD(referenceYear, 1, 1)
.difference(ee.Date('1970-01-01'), 'days')
.subtract(1)
return finalDay.add(dayOffset)
.multiply(1000) // Second to millis
.multiply(3600) // Hour to second
.multiply(24) // Day to hour
}
testDate(toMillis(ee.Image(1)), '2019-01-01')
testDate(toMillis(ee.Image(2)), '2019-01-02')
testDate(toMillis(ee.Image(3)), '2019-01-03')
testDate(toMillis(ee.Image(365)), '2019-12-31')
testDate(toMillis(ee.Image(366)), '2020-01-01')
testDate(toMillis(ee.Image(423)), '2020-02-27')
testDate(toMillis(ee.Image(424)), '2020-02-28')
testDate(toMillis(ee.Image(425)), '2020-03-01')
testDate(toMillis(ee.Image(426)), '2020-03-02')
testDate(toMillis(ee.Image(730)), '2020-12-31')
testDate(toMillis(ee.Image(731)), '2021-01-01')
testDate(toMillis(ee.Image(732)), '2021-01-02')
testDate(toMillis(ee.Image(1196)), '2022-04-11')
function testDate(millisImage, expectedDate) {
var millis = millisImage
.reduceRegion(ee.Reducer.first(), ee.Geometry.Point([0, 0]), 1)
.values()
.getNumber(0)
var date = ee.Date(millis).format('yyyy-MM-dd')
var valid = millis.eq(ee.Date(expectedDate).millis())
print(
ee.Algorithms.If(valid,
'Success: ' + expectedDate,
ee.String('Failed: Expected ' + expectedDate + ' was ').cat(date)
)
)
}
https://code.earthengine.google.com/16a23b3554e90c869c999de09e2fde90