0

I am having an image collection which contains two bands, one of them is called 'Date'. The format is in Julian format. However, for my analysis I need the dates in gregorian (normal calender i believe). I know that I can tranform each date using the function ee.Number.parse(ee.Date('2021-12-01').format('yyDDD')) if I want to convert from gregorian to Julian, but is it possible to map over the entire collection FROM Julian TO GREGORIAN without specifying each date?

My code is as follows:

var radd = ee.ImageCollection('projects/radar-wur/raddalert/v1');

print(radd);

var filterConfirmed = function(image){
  // get properties to copy over to output image
  var properties = image.propertyNames();
  
  // check if the 'Alert' property exists, if so, filter the confirmed alerts, if not set a new property called isBaseline
  var outImg = ee.Image(ee.Algorithms.If(

    // condition to check
    ee.List(image.bandNames()).contains('Alert'),     

    // do if true
    image.updateMask(image.select('Alert').eq(2))        // mask out pixels that are not Alert=2 
         .copyProperties(image, properties),

    // do if false
    ee.Image(0).set('isBaseline', 'baseline')));      
    
    return outImg;
  
};

// map over original collection and select the confirmed alerts (if band exists)
var raddConfirmedCollection = radd.map(filterConfirmed);

// remove images that have the 'isBaseline' property
var raddConfirmedCollection = raddConfirmedCollection.filter(ee.Filter.neq('isBaseline', 'baseline'));

Alternatively, I could also change the way the code reads by dates to Julian. For example, I have this:

var dateSelect1 = ui.Textbox({placeholder:'aaaa-mm-dd', value: '2021-03-01'});
var dateSelect2 = ui.Textbox({placeholder:'aaaa-mm-dd', value: '2021-05-01'});
panel.add(dateSelect1);
panel.add(dateSelect2);

var fecha1 = ee.Date(interfazUser.dateSelect1.getValue()); 
var fecha2 = ee.Date(interfazUser.dateSelect2.getValue());
var date1 = ee.Number(fecha1.getRelative('day','year')); //convert analysis dates to julian formats, 
var date2 = ee.Number(fecha2.getRelative('day','year'));
var dateYear1 = dateSelect1.slice(0,4);
var dateYear2 = dateSelect2.slice(0,4);

However, I do not know how to proceed. My code is not working, for example here:

var date1 = ee.Number(fecha1.getRelative('day','year'));
var date2 = ee.Number(fecha2.getRelative('day','year'));
var dateYear1 = dateSelect1.slice(0,4);
var dateYear2 = dateSelect2.slice(0,4);

var timeNow = ee.Date(Date.now());
var yearNow = timeNow.get('year');
var yearPre = timeNow.advance(-1,'year').get('year');
var yearNowS = ee.String(yearNow).getInfo();
var yearPreS = ee.String(yearPre).getInfo();
var yearNowShort = ee.String(yearNow).slice(2,4).getInfo();
var yearPreShort = ee.String(yearPre).slice(2,4).getInfo();

var bandasPre = ['Date' + yearPreShort,'Alert'+ yearPreShort];
var bandasAct = ['Date'+ yearNowShort,'Alert'+ yearNowShort];
var bandasRADD;
var raddfilter;
//var mosaicoLandsatEnero;
var raddLast;
var lastAlerts,lastAlerts2,lastAlerts3,lastAlerts4,lastAlerts5;
var raddRegion = raddConfirmedCollection.filterBounds(region); 
print(raddRegion, 'raddregion')


//Seleccion de alertas caso 1(añopre-añopre)
if(dateYear1 === yearPreS && dateYear2 === yearPreS ){
  raddfilter = raddRegion.filterDate(yearNowS +'-01-01',yearNowS +'-01-02');
  //raddfilter = raddRegion.filterDate(fecha1,fecha2);
  bandasRADD = bandasPre;
  //mosaicoLandsatEnero = funciones.landsatMosaic(ee.Date(yearPreS+'-01-01'),region).select(['red','nir','swir1','obsDate']);
  raddLast = raddfilter.sort('system:time_start',false).first();
  lastAlerts = raddLast.select(bandasRADD[1]).clip(region);
  lastAlerts2 = lastAlerts.selfMask();
  lastAlerts3 = lastAlerts2.where(raddLast.select(bandasRADD[0]).lt(date1),0);
  lastAlerts4 = lastAlerts3.where(raddLast.select(bandasRADD[0]).gt(date2),0);
  lastAlerts5 = lastAlerts4.selfMask();
}
//Seleccion de alertas caso 2(añopre-añoActual)
else {
if (dateYear1 === yearPreS && dateYear2 === yearNowS){
  radddfilter = raddRegion.filterDate(fecha1,fecha2);
  bandasRADD = bandasAct;
  //mosaicoLandsatEnero = funciones.landsatMosaic(fecha1,region).select(['red','nir','swir1','obsDate']);
  raddLast = raddfilter.sort('system:time_start',false).first();

  //Seleccion Año Pre
  lastAlerts = raddLast.select(bandasPre[1]).clip(region);
  var lastAlerts2_pre = lastAlerts.selfMask();
  var lastAlerts3_pre = lastAlerts2_pre.where(raddLast.select(bandasPre[0]).lt(date1),0);
  var lastAlerts5_pre = lastAlerts3_pre.selfMask().select([bandasPre[1]],[bandasAct[1]]);

  //Seleccion Año Actual
  lastAlerts = raddLast.select(bandasAct[1]).clip(region);
  var lastAlerts2_act = lastAlerts.selfMask();
  var lastAlerts3_act = lastAlerts2_act.where(raddLast.select(bandasAct[0]).gt(date2),0);
  var lastAlerts5_act = lastAlerts3_act.selfMask();
  
  //Union
  print(lastAlerts5_pre,lastAlerts5_act);
  lastAlerts2 = ee.ImageCollection.fromImages([lastAlerts2_pre.select([bandasPre[1]],[bandasAct[1]]),lastAlerts2_act]).reduce(ee.Reducer.lastNonNull()).select([bandasAct[1] +'_last'],[bandasAct[1]]);
  lastAlerts5 = ee.ImageCollection.fromImages([lastAlerts5_pre,lastAlerts5_act]).reduce(ee.Reducer.lastNonNull()).select([bandasAct[1] +'_last'],[bandasAct[1]]);
}
//Seleccion de alertas caso 3(añopre-añoActual)
else{
if (dateYear1 === yearNowS && dateYear2 === yearNowS){
  raddfilter = raddRegion.filterDate(fecha1,fecha2);
  bandasRADD = bandasAct;
  //mosaicoLandsatEnero = gladfilter.sort('system:time_start',true).first().select(['red','nir','swir1','obsDate']);
  radddLast = raddfilter.sort('system:time_start',false).first();
  lastAlerts = raddLast.select(bandasRADD[1]).clip(region);
  lastAlerts2 = lastAlerts.selfMask();
  lastAlerts3 = lastAlerts2.where(raddLast.select(bandasRADD[0]).lt(date1),0);
  lastAlerts4 = lastAlerts3.where(raddLast.select(bandasRADD[0]).gt(date2),0);
  lastAlerts5 = lastAlerts4.selfMask();
}}}

//var fechaExactaAlertayMosaico = ee.String(dateYear2).cat(ee.String('-')).cat(ee.String(raddLast.get('system:index')).slice(0,5).replace('_','-'));


print(dateYear2, 'dateyear2')
print(bandasRADD, 'bandasRADD')
print(raddfilter, 'radfilter')
//print(dateYear2,bandasRADD,raddRegion,raddfilter,fechaExactaAlertayMosaico);
print(dateYear2,bandasRADD,raddRegion,raddfilter)

//Imagen Landsat mes anterior
var fecha3 = fecha1.advance(-2,'month');
var fecha4 = fecha1.advance(-1,'day');
var raddfilter2 = raddRegion.filterDate(fecha3,fecha4);
var raddLast2 = raddfilter2.sort('system:time_start',false).first();

My raddfilter is empty, I think because it can not read the dates properly. The entire code can be found here: https://code.earthengine.google.com/251087daf2580acb000d77fc70e03bd8?accept_repo=users%2FPrioGLADpy%2Fui_ES

Can anyone help me?

3
  • Can you simply the problem to a smaller script? saves your potential helpers to go through 1200 lines of code..
    – Jobbo90
    Commented Mar 22, 2022 at 16:03
  • It depends what you want to do with the pixel values. You can refer to this question for an explanation for why using an (integer) Gregorian format is not suitable for analysis.
    – Matt
    Commented Mar 24, 2022 at 14:14
  • I just want them in a more 'readable' format. But as I understand, once I specified how my code 'reads' the dates (format yy-ddd), it works.. However, it can still not perform the function.. a shorter code to the question can be found here:code.earthengine.google.com/dfcad338aab040ebbe0a751c80b1a7f7
    – LouLou
    Commented Mar 24, 2022 at 16:16

1 Answer 1

2

Your question is not clear to me. First, I'll boil this down as far as I can. It doesn't matter if you have an image collection, or if each image in that collection contains multiple bands. You have images where each pixel value represents a date. They're "formatted" as yyDDD. So, a pixel value of 21030 represents the date 2021-01-30.

You're asking how to convert such an image to a different format. You say you want to convert FROM Julian TO GREGORIAN. However, I would argue that you don't actually start with a Julian date. According to this, the Julian date for 2021-01-30 is 2459244.5, not 21030.

You're working with an image where dates are pixel values, not image properties, hence these dates can only be represent as numbers, I'm not sure what format you want to convert the dates to. Your idea of using ee.Date doesn't work when you're working with pixel values. It would be fine if the date was an image property.

Now, if you wanted to convert these dates to actual Julian dates, that's tricky, and an interesting challenge. I understand that it's not the question you're actually asking, but maybe it can give you some ideas how you can work with these types of date bands. Inspect the pixel values in the resulting layers:

var date = randomDateImage()
Map.addLayer(date, null, 'date')

var julian = toJulianDate(date)
Map.addLayer(julian, null, 'julian')
// Validate here: https://ssd.jpl.nasa.gov/tools/jdc/#/jd


function toJulianDate(yyDDD) {
  // With the yyDDD date format, it's impossible to tell which century the date is in. 
  // Here we assume it's 2000.
  var year = yyDDD.divide(1000).int8()
    .add(2000)
  var dayOfYear = yyDDD.mod(1000)

  var leapYears = ee.Image(ee.Array( // Array image with leap years 
    ee.List.sequence(1901, 2050)
      .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.lt(year)) // 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

  // https://www.typecalendar.com/julian-date
  return ee.Image().expression(
    '2415020 + 365 * (year - 1900) + N + L - 0.5', {
      year: year,
      N: dayOfYear,
      L: numberOfLeapYears
    }
  )
}

function randomDateImage() {
  var year = ee.Image.random().multiply(22).int8()
  var dayOfYear = ee.Image.random().multiply(364).int16()
  return year.multiply(1000).add(dayOfYear)
}

https://code.earthengine.google.com/61650eda74a5e84807fcb99368d0803f

1
  • Thank you so much for trying to help me! I think you are right, maybe I do not want to transform it but rather format it to Julian. Is that possible? Or would you suggest to change the way the user is typing in the dates to the format of Julian?
    – LouLou
    Commented Mar 23, 2022 at 11:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.