Primeng: Add Timezone Support to <p-calendar/>

Created on 7 Nov 2018  路  4Comments  路  Source: primefaces/primeng

I'm submitting a ... (check one with "x")

[ ] bug report => Search github for a similar issue or PR before submitting
[X] feature request => Please check if request is not on the roadmap already https://github.com/primefaces/primeng/wiki/Roadmap
[ ] support request => Please do not submit support request here, instead see http://forum.primefaces.org/viewforum.php?f=35

Current behavior
Currently, any date captured with the <p-calendar/> is considered to be entered with respect to the client's browser. If someone in the America/Los_Angeles zone selects 2018-01-01, the component's value really is 2018-01-01T08:00:00.000Z, while a user with the America/New_York zone would have the value 2018-01-01T05:00:00.000Z:

| Selected Date | Client Timezone | UTC |
| ------------- | ------------- |------------- |
| 2018-01-01 | America/New_York | 2018-01-01T05:00:00.000Z |
| 2018-01-01 | America/Chicago | 2018-01-01T06:00:00.000Z |
| 2018-01-01 | America/Denver | 2018-01-01T07:00:00.000Z |
| 2018-01-01 | America/Los_Angeles | 2018-01-01T08:00:00.000Z |

There is a difference of an hour between each zone, and this is the standard and correct behavior by default because the user is most likely intending to enter the date in their own timezone.

Expected behavior
Support should be added to allow the timezone to be set as either an application wide value or perhaps as a property of the component instance. This would change the <p-calendar/> so that the entered date is in respect to the provided zone. Using the example from above, if someone in the America/Los_Angeles zone selects 2018-01-01, and the component was set to the America/New_York zone, the components absolute value would be 2018-01-01T05:00:00.000Z.

| Selected Date | Client Timezone | Component Zone | UTC |
| ------------- | ------------- |------------- |------------- |
| 2018-01-01 | America/New_York | America/New_York | 2018-01-01T05:00:00.000Z |
| 2018-01-01 | America/Chicago | America/New_York | 2018-01-01T05:00:00.000Z |
| 2018-01-01 | America/Denver | America/New_York | 2018-01-01T05:00:00.000Z |
| 2018-01-01 | America/Los_Angeles | America/New_York | 2018-01-01T05:00:00.000Z |

As you can see above, the value of the component is always the same regardless of the user's machine's zone.

What is the motivation / use case for changing the behavior?
In our application, the business rules dictate that all user entered datetimes are relative to the America/New_York zone and should be captured and displayed as such for consistency. (However, this can be modified at the application level to another zone). Currently, this is impossible with the <p-calendar/> as it stands and I've been Monkey Patching it:

@Directive({
  selector: 'p-calendar'//only mount on p-calendars
})
export class ZonedDateComponent implements OnInit, OnDestroy {

  subscriptions: Subscription[]

  constructor(
    private appService: AppService,
    @Host() @Self() @Optional() private calendar: Calendar//the instance we're mounted on
  ) {

    //monkey patch internal methods :(
    calendar.formatDate = (date: Date, formatBinding: string) => {
      return moment(date).tz(this.timezone).formatWithJDF('MM/dd/yyyy');//ignoring formatBinding because it's a non-standard format
    };

    calendar.formatTime = (date: Date) => {
      let hourFormat = calendar.hourFormat == '12' ? 'hh a' : 'HH';
      return moment(date).tz(this.timezone).formatWithJDF(`${hourFormat}:mm`);
    };

  }

  ngOnInit() {
    this.subscriptions = [
      this.calendar.onSelect.subscribe((d) => this.transformDateToZone(d)),
      this.calendar.onInput.subscribe(event => {
        if (this.calendar.value) { //this means the input was accepted as valid
          this.transformDateToZone(this.calendar.value);//we should transform the date
        }
      })
    ];
  }

  ngOnDestroy() {
    this.subscriptions.forEach(s => s.unsubscribe());
  }

  transformDateToZone(capturedDate: Date) {//strip timezone from date and force into configured zone
    let zonedDate = dateUtil.convertToZone(capturedDate, this.timezone);
    this.calendar.updateModel(zonedDate);//this is a private api. In the future, we'll try to avoid using it.
  }


  get timezone(){
    return this.appService.timezone;
  }

}

This works for basic calendar inputs, but it's flawed, and the complexity of monkey patching is not ideal because we basically have to patch every method and we constantly have to maintain the patches between primeng versions. For example, I just discovered the calendar's highlighted today date is currently dependent on the client's zone. I would love to hear everyone's thoughts on the issue as I'm sure we're not the only ones dealing with timezones. I would also like to hear any ideas for an alternate implementation.

Most helpful comment

Oh, it's still open, how to work around it? i really don't like maintain a project with primeng.

All 4 comments

They had date UTC... and they chose to remove it #5853 Me personally, I hope I had never used primeng in the first place.

Oh, it's still open, how to work around it? i really don't like maintain a project with primeng.

Due to complexity it brings, none of the datepickers (PrimeFaces, PrimeNG, PrimeReact, PrimeVue) have built-in support for timezones as it can be handled by the page author easier.

@cagataycivici With all due respect, you didn't address ANY of the concerns of the op. We are all grateful for the work you do on this library, but to brush aside the real concerns of dev users is short-sighted. Saying "it can be handled by the page author easier" is just flat out lazy, especially for a component library published with the intent of others using it. This is a real problem. Are you guaranteeing that Calendar.updateModel() will always be available and never removed? Are you going to put it in the documentation that zoned dates "can be handled by the page authors easier" by updating the model using updateModel()? Will you publish a guide in the documentation on all intricacies (such as today using the clients zone) and what to do to handle it? Devs drop libraries because of stuff like this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

miresk picture miresk  路  3Comments

markgoho picture markgoho  路  3Comments

watalberto picture watalberto  路  3Comments

papiroca-tm picture papiroca-tm  路  3Comments

pchristou picture pchristou  路  3Comments