Repository: flatpickr/flatpickr
Pull request #2600 (2022-01-10 07:11:06)

Fix issues with parsing localized date/time
Hello 👋 
I'm a maintainer of [RailsAdmin](https://github.com/railsadminteam/rails_admin) project and currently [working on](https://github.com/railsadminteam/rails_admin/pull/3455) integrating flatpickr into that. Thank you for the hard work of publishing and maintaining this great project!

During the integration, I found some issues related to handling of localized date/time values. Please refer to the commits for details.

If there's anything I can do to get this merged please let me know, thanks!


Patch:
diff --git a/src/index.ts b/src/index.ts
index c44dad09..496fcdaf 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2155,6 +2155,10 @@ function FlatpickrInstance(
         : undefined),
     };
 
+    tokenRegex.D = `(${self.l10n.weekdays.shorthand.join("|")})`;
+    tokenRegex.l = `(${self.l10n.weekdays.longhand.join("|")})`;
+    tokenRegex.M = `(${self.l10n.months.shorthand.join("|")})`;
+    tokenRegex.F = `(${self.l10n.months.longhand.join("|")})`;
     tokenRegex.K = `(${self.l10n.amPM[0]}|${
       self.l10n.amPM[1]
     }|${self.l10n.amPM[0].toLowerCase()}|${self.l10n.amPM[1].toLowerCase()})`;
diff --git a/src/utils/formatting.ts b/src/utils/formatting.ts
index 74b1b343..83799115 100644
--- a/src/utils/formatting.ts
+++ b/src/utils/formatting.ts
@@ -47,7 +47,7 @@ export const revFormat: RevFormat = {
     dateObj.setMonth(locale.months.longhand.indexOf(monthName));
   },
   G: (dateObj: Date, hour: string) => {
-    dateObj.setHours(parseFloat(hour));
+    dateObj.setHours((dateObj.getHours() >= 12 ? 12 : 0) + parseFloat(hour));
   },
   H: (dateObj: Date, hour: string) => {
     dateObj.setHours(parseFloat(hour));
@@ -93,7 +93,7 @@ export const revFormat: RevFormat = {
     dateObj.setDate(parseFloat(day));
   },
   h: (dateObj: Date, hour: string) => {
-    dateObj.setHours(parseFloat(hour));
+    dateObj.setHours((dateObj.getHours() >= 12 ? 12 : 0) + parseFloat(hour));
   },
   i: (dateObj: Date, minutes: string) => {
     dateObj.setMinutes(parseFloat(minutes));
@@ -121,13 +121,13 @@ export const revFormat: RevFormat = {
 
 export type TokenRegex = { [k in token]: string };
 export const tokenRegex: TokenRegex = {
-  D: "(\\w+)",
-  F: "(\\w+)",
+  D: "", // locale-dependent, setup on runtime
+  F: "", // locale-dependent, setup on runtime
   G: "(\\d\\d|\\d)",
   H: "(\\d\\d|\\d)",
   J: "(\\d\\d|\\d)\\w+",
   K: "", // locale-dependent, setup on runtime
-  M: "(\\w+)",
+  M: "", // locale-dependent, setup on runtime
   S: "(\\d\\d|\\d)",
   U: "(.+)",
   W: "(\\d\\d|\\d)",
@@ -137,7 +137,7 @@ export const tokenRegex: TokenRegex = {
   h: "(\\d\\d|\\d)",
   i: "(\\d\\d|\\d)",
   j: "(\\d\\d|\\d)",
-  l: "(\\w+)",
+  l: "", // locale-dependent, setup on runtime
   m: "(\\d\\d|\\d)",
   n: "(\\d\\d|\\d)",
   s: "(\\d\\d|\\d)",


Test patch:
diff --git a/__tests__/src/index.spec.ts b/__tests__/src/index.spec.ts
index b4fcf394..e0ad7fad 100644
--- a/__tests__/src/index.spec.ts
+++ b/__tests__/src/index.spec.ts
@@ -1,4 +1,7 @@
 import flatpickr from "index";
+import { French } from "l10n/fr";
+import { Irish } from "l10n/ga";
+import { Japanese } from "l10n/ja";
 import { Russian } from "l10n/ru";
 import { Instance, DayElement } from "types/instance";
 import { Options, DateRangeLimit } from "types/options";
@@ -262,6 +265,36 @@ describe("flatpickr", () => {
         expect(date.getTime()).toBeDefined();
         expect(date.getTime()).toEqual(Date.parse("2016-12-27T16:16:22.585Z"));
       });
+
+      it("should parse string with unicode characters", () => {
+        createInstance({
+          defaultDate: "03 février 2021",
+          dateFormat: "d F Y",
+          locale: French,
+        });
+
+        expect(fp.selectedDates[0]).toEqual(new Date("2021-02-03T00:00:00"));
+      });
+
+      it("should parse string with space contained in month names", () => {
+        createInstance({
+          defaultDate: "Dé Domhnaigh 5 Meán Fómhair 2021",
+          dateFormat: "l j F Y",
+          locale: Irish,
+        });
+
+        expect(fp.selectedDates[0]).toEqual(new Date("2021-09-05T00:00:00"));
+      });
+
+      it("should parse string without delimiters", () => {
+        createInstance({
+          defaultDate: "2021年2月3日",
+          dateFormat: "Y年Fj日",
+          locale: Japanese,
+        });
+
+        expect(fp.selectedDates[0]).toEqual(new Date("2021-02-03T00:00:00"));
+      });
     });
 
     describe("time string parser", () => {
@@ -356,6 +389,19 @@ describe("flatpickr", () => {
 
         expect((fp.hourElement as HTMLInputElement).value).toEqual("23");
       });
+
+      it("should parse string which has meridian indicator before hour", () => {
+        createInstance({
+          enableTime: true,
+          noCalendar: true,
+          dateFormat: "Kh時",
+          defaultDate: "午後3時",
+          locale: Japanese,
+        });
+
+        expect(fp.selectedDates[0]).toBeDefined();
+        expect(fp.selectedDates[0].getHours()).toBe(15);
+      });
     });
   });
 
@@ -395,7 +441,7 @@ describe("flatpickr", () => {
 
         fp.setDate("Thu 20 October, '16");
         expect(fp.input.value).toEqual(RESULT);
-        fp.setDate("2015-11-21 19:29:49");
+        fp.setDate("2015-11-21T19:29:49Z");
         expect(fp.input.value).not.toEqual(RESULT);
       });
     });