ngx-bootstrap: DatePicker timezone problem

[bsConfig]="{ dateInputFormat: 'YYYY-MM-DD' }"

when this format is used, i may expect the same entry come back regardless of client. because we are selecting a date not datetime. But its considering it as datetime and puts timezone info to it.

So, for example, 2018-01-30 00:00:00 becomes 2018-01-29 if your timezone is +

There is no config option to set timezone or any thing that allows to retreive the input directly.

If there is a way, i am not aware but per the source code, i dont see any option that lets this.

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 70
  • Comments: 48 (8 by maintainers)

Most upvoted comments

Any idea when a fix will be available?

I came to check this issue after 1 year and mods still need info about the issue. Maybe in year 3020 they will find root cause and in year 4020 it is expected to be solved.

why is this closed… still a problem and no solution!?

@isalox you could try my workaround solution that i post before. a utc date wrapper for ngx-bootstrap for version before 5.2.0 @Domainv No. Still have some problem in https://stackblitz.com/edit/angular-mb7szh. It work fine when setDate button is pressed. But when the date is selected by datepicker, it do not work.

image

image

image

I don’t need any workarounds. It should work properly without any hacks. It is basic functionality for datepicker. If it can’t render date correctly why do anyone need it. Right now it is useless. Hope it will be fixed in next release.

its 2 years from first post and this issues is not fix ?

this is solved the issue <input id="input-dateOfBirth" class="form-control" type="text" bsDatepicker name="dateOfBirth" placeholder="Birth Date" [(ngModel)]="dateOfBirth" ng-model-options="{timezone: 'local'}" />

here is example: https://stackblitz.com/edit/angular-usdq2z

Really?!? We need to a special custom function to handle such a simple problem!? This is so stupid!

@Omi231 very funny joke, thanks I wish, that such people, like you, who can only post some silly jokes, also, post some code snippets with help, or, even PRs with fixes / features

Help us!!!

Thanks, guys, I’ll fix it as soon as possible.

Same problem!

Released ngx-bootstrap@5.3.2

behavior was back as in 5.1.2 version

Needs more info and time to find the correct solution for timezone issue

@isalox Provide more info, please. Some reproduction.

take a look here: https://stackblitz.com/edit/angular-vbku3b

just click Set Date and you will see in control date 1 day back

after an afternoon and an evening plenty of frustration, I switched to a simple input control type=date and the date is saved without time, what I needed for my case

I had the same issue, for some reasons, bsDatepicker always picked the day before the date you choose. Here is a solution I found which uses datepipe from angular/common.

let dateFromBsdatepicker:Date = reactiveForm[‘formControlName’]; let correctDate = this.datepipe.transform(dateFromBsdatepicker,‘yyyy-MM-dd’);

A quick workaround in my case is to avoid moment in formatting the date before using it in this datepicker… Like, i had moment(date).format("MM/DD/YYYY") which i changed to new Date(date) Yes, simply this helped me to fix this, also my API response supported this change… Now it works fine…

@dinhanhthi I made wrapper around this component and use it instead. If you do not need all original Inputs and Outputs it should be easy and small component.

export function getDateWithoutOffset(value: string): Date {
  const date = moment(value).utcOffset(value);
  return moment({ year: date.year(), month: date.month(), date: date.date() }).toDate();
}

utc-datepicker.component.ts

import { Component, forwardRef, Input } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker/bs-datepicker.config';

@Component({
  selector: 'app-utc-datepicker',
  templateUrl: './utc-datepicker.component.html',
  styleUrls: ['./utc-datepicker.component.scss'],
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => UtcDatepickerComponent),
      multi: true,
    },
  ],
})
export class UtcDatepickerComponent implements ControlValueAccessor {
  @Input() showDatePickerOnFieldClick = false;
  @Input() disabled = false;
  @Input() showToggleButton = true;
  @Input() set bsConfig(config: Partial<BsDatepickerConfig>) {
    this._bsConfig = {
      showWeekNumbers: false,
      containerClass: 'theme-dark-blue',
      ...config,
    } as BsDatepickerConfig;
  }
  get bsConfig() {
    return this._bsConfig;
  }

  value: any;
  private _bsConfig: BsDatepickerConfig;

  onChange: (value: any) => void = () => {
    /**
     * Do nothing
     */
  };
  onTouched: (value: any) => void = () => {
    /**
     * Do nothing
     */
  };

  bsValueChange(val) {
    setTimeout(() => {
      this.value = val;
      if (val) {
        this.onTouched(val);
      }
      if (val instanceof Date) {
        this.onChange(
          new Date(val.getTime() - val.getTimezoneOffset() * 60 * 1000)
        );
      } else if (val !== undefined) {
        // This condition is because if undefined is default value it will trigger dirty check and show error message
        this.onChange(val);
      }
    });
  }

  writeValue(val: any): void {
    if (val) {
      if (val instanceof Date) {
        this.value = new Date(
          val.getTime() + val.getTimezoneOffset() * 60 * 1000
        );
      } else if (typeof val === 'string') {
        this.value = getDateWithoutOffset(val);
      } else {
        console.warn('Expected Date or string - unexpected value', val);
      }
    }
  }

  registerOnChange(fn: (value: any) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
}

utc-datepicker.component.html

<div
  class="input-group mb-3"
  (click)="showDatePickerOnFieldClick ? birthDatePicker.show() : {}"
>
  <input
    type="text"
    [ngClass]="{ 'form-control': true, 'input-clickable': showDatePickerOnFieldClick }"
    bsDatepicker
    #birthDatePicker="bsDatepicker"
    [disabled]="disabled"
    [bsConfig]="bsConfig"
    [bsValue]="value"
    (bsValueChange)="bsValueChange($event)"
  />
  <div class="input-group-append" *ngIf="showToggleButton">
    <span
      class="input-group-text"
      id="inputGroupPrepend"
      (click)="birthDatePicker.show()"
    >
      <i class="fa fa-calendar"></i>
    </span>
  </div>
</div>

Usage example:

          <app-utc-datepicker
            [bsConfig]="{ maxDate: maximumDate, minDate: minimumDate }"
            [disabled]="true"
            [showDatePickerOnFieldClick]="true"
            formControlName="date"
          >
          </app-utc-datepicker>

@isalox you could try my workaround solution that i post before. a utc date wrapper for ngx-bootstrap for version before 5.2.0 @Domainv No. Still have some problem in https://stackblitz.com/edit/angular-mb7szh. It work fine when setDate button is pressed. But when the date is selected by datepicker, it do not work.

image

image

image

And that is why i need a wrapper for my workaround solution. As my situation, i need a datepicker for UTC+0 situation. Actually, I need a wrapper to handle problem of UTC + 0, UTC + Custom Timezone and also browser timezone.

it is just for example. Actually my problem is when I am getting data from Rest API. In data base, i store only dates without time. That data is send to UI and deserializes and when I want to edit I am getting dates one day back.

https://medium.com/self-learning/ngx-datepicker-utc-datepicker-design-77e33789e9d7

I have tried a UTC Datepicker which is a wrapper to original datepicker. The wrapper try to convert the input with a timezone offset procession.

image

import { Component, OnInit, forwardRef, ChangeDetectorRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';

@Component({
  selector: 'app-utc-datepicker',
  templateUrl: './utc-datepicker.component.html',
  styleUrls: ['./utc-datepicker.component.css'],
  providers: [{
    provide: NG_VALUE_ACCESSOR,
    useExisting: forwardRef(() => UtcDatepickerComponent),
    multi: true
  }]
})
export class UtcDatepickerComponent implements OnInit, ControlValueAccessor{

  value: any;

  constructor() { }

  onChange: (value: any) => void;

  ngOnInit() {
  }

  bsValueChange(val){
    setTimeout(()=>{
      this.value = val;
      if (val instanceof Date){
        this.onChange(new Date(val.getTime() - val.getTimezoneOffset() * 60 * 1000));  
      }else {
        this.onChange(val);
      }
    });
  }

  writeValue(val: any): void {
    if (val){
      if (val instanceof Date){
        this.value = new Date(val.getTime() + val.getTimezoneOffset() * 60 * 1000);
      }else {
        this.value = val;
      }
    }
  }

  registerOnChange(fn: (value: any) => void): void {
    this.onChange = fn;
  }

  registerOnTouched(fn: any): void {
  }
  

}

Remark for this solution All time input should be converted to a time with a specific processing of timezone offset such as min day, max day handling.

same problem, datepicker return one day behind

it doesn’t work in 5.2.0 version

This is actually expected date behaviour in js. And yes js Dates is a pain. Just call .toUTCstring() and you should see the same date

Same Problem Here. Can you post some example code? How many years this issue exists?? Isn’t this a bit unacceptable??