Skip to content

Commit

Permalink
Merge pull request #1054 from iamkun/dev
Browse files Browse the repository at this point in the history
D2M
  • Loading branch information
iamkun authored Sep 17, 2020
2 parents 82b5034 + a882b20 commit 8b4fc53
Show file tree
Hide file tree
Showing 19 changed files with 261 additions and 23 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ coverage
/dayjs.min.js
/esm
/index.d.ts
locale.json

#dev
demo.js
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ cache:
- ~/.npm
- node_modules
node_js:
- '14'
- '12'
- '10'
- '8'
Expand Down
22 changes: 21 additions & 1 deletion build/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,34 @@ const { ncp } = require('ncp')
const { promisify } = util

const promisifyReadDir = promisify(fs.readdir)
const promisifyReadFile = promisify(fs.readFile)
const promisifyWriteFile = promisify(fs.writeFile)

const localeNameRegex = /\/\/ (.*) \[/
const formatName = n => n.replace(/\.js/, '').replace('-', '_')

const localePath = path.join(__dirname, '../src/locale')

async function build(option) {
const bundle = await rollup.rollup(option.input)
await bundle.write(option.output)
}

async function listLocaleJson(localeArr) {
const localeListArr = []
await Promise.all(localeArr.map(async (l) => {
const localeData = await promisifyReadFile(path.join(localePath, l), 'utf-8')
localeListArr.push({
key: l.slice(0, -3),
name: localeData.match(localeNameRegex)[1]
})
}))
promisifyWriteFile(path.join(__dirname, '../locale.json'), JSON.stringify(localeListArr), 'utf8')
}

(async () => {
try {
const locales = await promisifyReadDir(path.join(__dirname, '../src/locale'))
const locales = await promisifyReadDir(localePath)
locales.forEach((l) => {
build(configFactory({
input: `./src/locale/${l}`,
Expand All @@ -42,6 +59,9 @@ async function build(option) {
}))

await promisify(ncp)('./types/', './')

// list locales
await listLocaleJson(locales)
} catch (e) {
console.error(e) // eslint-disable-line no-console
}
Expand Down
41 changes: 41 additions & 0 deletions src/locale/am.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Amharic [am]
import dayjs from 'dayjs'

const locale = {
name: 'am',
weekdays: 'እሑድ_ሰኞ_ማክሰኞ_ረቡዕ_ሐሙስ_አርብ_ቅዳሜ'.split('_'),
weekdaysShort: 'እሑድ_ሰኞ_ማክሰ_ረቡዕ_ሐሙስ_አርብ_ቅዳሜ'.split('_'),
weekdaysMin: 'እሑ_ሰኞ_ማክ_ረቡ_ሐሙ_አር_ቅዳ'.split('_'),
months: 'ጃንዋሪ_ፌብሯሪ_ማርች_ኤፕሪል_ሜይ_ጁን_ጁላይ_ኦገስት_ሴፕቴምበር_ኦክቶበር_ኖቬምበር_ዲሴምበር'.split('_'),
monthsShort: 'ጃንዋ_ፌብሯ_ማርች_ኤፕሪ_ሜይ_ጁን_ጁላይ_ኦገስ_ሴፕቴ_ኦክቶ_ኖቬም_ዲሴም'.split('_'),
weekStart: 1,
yearStart: 4,
relativeTime: {
future: 'በ%s',
past: '%s በፊት',
s: 'ጥቂት ሰከንዶች',
m: 'አንድ ደቂቃ',
mm: '%d ደቂቃዎች',
h: 'አንድ ሰዓት',
hh: '%d ሰዓታት',
d: 'አንድ ቀን',
dd: '%d ቀናት',
M: 'አንድ ወር',
MM: '%d ወራት',
y: 'አንድ ዓመት',
yy: '%d ዓመታት'
},
formats: {
LT: 'HH:mm',
LTS: 'HH:mm:ss',
L: 'DD/MM/YYYY',
LL: 'MMMM D ፣ YYYY',
LLL: 'MMMM D ፣ YYYY HH:mm',
LLLL: 'dddd ፣ MMMM D ፣ YYYY HH:mm'
},
ordinal: n => `${n}ኛ`
}

dayjs.locale(locale, null, true)

export default locale
1 change: 1 addition & 0 deletions src/locale/bi.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Bislama [bi]
import dayjs from 'dayjs'

const locale = {
Expand Down
1 change: 1 addition & 0 deletions src/locale/en.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// English [en]
// We don't need weekdaysShort, weekdaysMin, monthsShort in en.js locale
export default {
name: 'en',
Expand Down
12 changes: 6 additions & 6 deletions src/locale/fi.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,13 @@ const locale = {
LT: 'HH.mm',
LTS: 'HH.mm.ss',
L: 'DD.MM.YYYY',
LL: 'Do MMMM[ta] YYYY',
LLL: 'Do MMMM[ta] YYYY, [klo] HH.mm',
LLLL: 'dddd, Do MMMM[ta] YYYY, [klo] HH.mm',
LL: 'D. MMMM[ta] YYYY',
LLL: 'D. MMMM[ta] YYYY, [klo] HH.mm',
LLLL: 'dddd, D. MMMM[ta] YYYY, [klo] HH.mm',
l: 'D.M.YYYY',
ll: 'Do MMM YYYY',
lll: 'Do MMM YYYY, [klo] HH.mm',
llll: 'ddd, Do MMM YYYY, [klo] HH.mm'
ll: 'D. MMM YYYY',
lll: 'D. MMM YYYY, [klo] HH.mm',
llll: 'ddd, D. MMM YYYY, [klo] HH.mm'
}
}

Expand Down
23 changes: 18 additions & 5 deletions src/locale/hr.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
// Croatian [hr]
import dayjs from 'dayjs'

const monthFormat = 'siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca'.split('_')
const monthStandalone = 'siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_')
const MONTHS_IN_FORMAT = /D[oD]?(\[[^[\]]*\]|\s)+MMMM?/

const months = (dayjsInstance, format) => {
if (MONTHS_IN_FORMAT.test(format)) {
return monthFormat[dayjsInstance.month()]
}
return monthStandalone[dayjsInstance.month()]
}
months.s = monthStandalone
months.f = monthFormat

const locale = {
name: 'hr',
weekdays: 'Nedjelja_Ponedjeljak_Utorak_Srijeda_Četvrtak_Petak_Subota'.split('_'),
weekdaysShort: 'Ned._Pon._Uto._Sri._Čet._Pet._Sub.'.split('_'),
weekdaysMin: 'Ne_Po_Ut_Sr_Če_Pe_Su'.split('_'),
months: 'Siječanj_Veljača_Ožujak_Travanj_Svibanj_Lipanj_Srpanj_Kolovoz_Rujan_Listopad_Studeni_Prosinac'.split('_'),
monthsShort: 'Sij._Velj._Ožu._Tra._Svi._Lip._Srp._Kol._Ruj._Lis._Stu._Pro.'.split('_'),
weekdays: 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
weekdaysShort: 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
weekdaysMin: 'ne_po_ut_sr_če_pe_su'.split('_'),
months,
monthsShort: 'sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'),
weekStart: 1,
formats: {
LT: 'H:mm',
Expand Down
16 changes: 15 additions & 1 deletion src/locale/lt.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
// Lithuanian [lt]
import dayjs from 'dayjs'

const monthFormat = 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_')
const monthStandalone = 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_')
// eslint-disable-next-line no-useless-escape
const MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/

const months = (dayjsInstance, format) => {
if (MONTHS_IN_FORMAT.test(format)) {
return monthFormat[dayjsInstance.month()]
}
return monthStandalone[dayjsInstance.month()]
}
months.s = monthStandalone
months.f = monthFormat

const locale = {
name: 'lt',
weekdays: 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'),
weekdaysShort: 'sek_pir_ant_tre_ket_pen_šeš'.split('_'),
weekdaysMin: 's_p_a_t_k_pn_š'.split('_'),
months: 'sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis'.split('_'),
months,
monthsShort: 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'),
ordinal: n => `${n}.`,
weekStart: 1,
Expand Down
20 changes: 17 additions & 3 deletions src/locale/pl.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,26 @@ function translate(number, withoutSuffix, key) {
}
}
/* eslint-enable */

const monthFormat = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_')
const monthStandalone = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_')
const MONTHS_IN_FORMAT = /D MMMM/

const months = (dayjsInstance, format) => {
if (MONTHS_IN_FORMAT.test(format)) {
return monthFormat[dayjsInstance.month()]
}
return monthStandalone[dayjsInstance.month()]
}
months.s = monthStandalone
months.f = monthFormat

const locale = {
name: 'pl',
weekdays: 'Niedziela_Poniedziałek_Wtorek_Środa_Czwartek_Piątek_Sobota'.split('_'),
weekdaysShort: 'Ndz_Pon_Wt_Śr_Czw_Pt_Sob'.split('_'),
weekdays: 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'),
weekdaysShort: 'ndz_pon_wt_śr_czw_pt_sob'.split('_'),
weekdaysMin: 'Nd_Pn_Wt_Śr_Cz_Pt_So'.split('_'),
months: 'Styczeń_Luty_Marzec_Kwiecień_Maj_Czerwiec_Lipiec_Sierpień_Wrzesień_Październik_Listopad_Grudzień'.split('_'),
months,
monthsShort: 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'),
ordinal: n => `${n}.`,
weekStart: 1,
Expand Down
3 changes: 2 additions & 1 deletion src/plugin/duration/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MILLISECONDS_A_WEEK, MILLISECONDS_A_DAY, MILLISECONDS_A_HOUR, MILLISECONDS_A_MINUTE, MILLISECONDS_A_SECOND } from '../../constant'
import { MILLISECONDS_A_DAY, MILLISECONDS_A_HOUR, MILLISECONDS_A_MINUTE, MILLISECONDS_A_SECOND, MILLISECONDS_A_WEEK } from '../../constant'

const MILLISECONDS_A_YEAR = MILLISECONDS_A_DAY * 365
const MILLISECONDS_A_MONTH = MILLISECONDS_A_DAY * 30
Expand All @@ -12,6 +12,7 @@ const unitToMS = {
hours: MILLISECONDS_A_HOUR,
minutes: MILLISECONDS_A_MINUTE,
seconds: MILLISECONDS_A_SECOND,
milliseconds: 1,
weeks: MILLISECONDS_A_WEEK
}

Expand Down
30 changes: 27 additions & 3 deletions src/plugin/timezone/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const typeToPos = {
const ms = 'ms'

export default (o, c, d) => {
let defaultTimezone

const localUtcOffset = d().utcOffset()
const tzOffset = (timestamp, timezone) => {
const date = new Date(timestamp)
Expand All @@ -33,33 +35,51 @@ export default (o, c, d) => {
filled[pos] = parseInt(value, 10)
}
}
const utcString = `${filled[0]}-${filled[1]}-${filled[2]} ${filled[3]}:${filled[4]}:${filled[5]}:000`
// Workaround for the same behavior in different node version
// https://github.com/nodejs/node/issues/33027
const hour = filled[3]
const fixedHour = hour === 24 ? 0 : hour
const utcString = `${filled[0]}-${filled[1]}-${filled[2]} ${fixedHour}:${filled[4]}:${filled[5]}:000`
const utcTs = d.utc(utcString).valueOf()
let asTS = +date
const over = asTS % 1000
asTS -= over
return (utcTs - asTS) / (60 * 1000)
}

// find the right offset a given local time. The o input is our guess, which determines which
// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)
// https://github.com/moment/luxon/blob/master/src/datetime.js#L76
const fixOffset = (localTS, o0, tz) => {
// Our UTC time is just a guess because our offset is just a guess
let utcGuess = localTS - (o0 * 60 * 1000)
// Test whether the zone matches the offset for this ts
const o2 = tzOffset(utcGuess, tz)
// If so, offset didn't change and we're done
if (o0 === o2) {
return [utcGuess, o0]
}
// If not, change the ts by the difference in the offset
utcGuess -= (o2 - o0) * 60 * 1000
// If that gives us the local time we want, we're done
const o3 = tzOffset(utcGuess, tz)
if (o2 === o3) {
return [utcGuess, o2]
}
// If it's different, we're in a hole time.
// The offset has changed, but the we don't adjust the time
return [localTS - (Math.min(o2, o3) * 60 * 1000), Math.max(o2, o3)]
}

const proto = c.prototype
proto.tz = function (timezone) {

proto.tz = function (timezone = defaultTimezone) {
const target = this.toDate().toLocaleString('en-US', { timeZone: timezone })
const diff = Math.round((this.toDate() - new Date(target)) / 1000 / 60)
return d(target).utcOffset(localUtcOffset - diff, true).$set(ms, this.$ms)
}
d.tz = function (input, timezone) {

d.tz = function (input, timezone = defaultTimezone) {
const previousOffset = tzOffset(+d(), timezone)
let localTs
if (typeof input !== 'string') {
Expand All @@ -75,4 +95,8 @@ export default (o, c, d) => {
d.tz.guess = function () {
return Intl.DateTimeFormat().resolvedOptions().timeZone
}

d.tz.setDefault = function (timezone) {
defaultTimezone = timezone
}
}
18 changes: 18 additions & 0 deletions test/locale/hr.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import moment from 'moment'
import dayjs from '../../src'
import '../../src/locale/hr'

it('Format month with locale function', () => {
for (let i = 0; i <= 7; i += 1) {
const dayjsUK = dayjs().locale('hr').add(i, 'day')
const momentUK = moment().locale('hr').add(i, 'day')
const testFormat1 = 'DD MMMM YYYY MMM'
const testFormat2 = 'dddd, MMMM D YYYY'
const testFormat3 = 'MMMM'
const testFormat4 = 'MMM'
expect(dayjsUK.format(testFormat1)).toEqual(momentUK.format(testFormat1))
expect(dayjsUK.format(testFormat2)).toEqual(momentUK.format(testFormat2))
expect(dayjsUK.format(testFormat3)).toEqual(momentUK.format(testFormat3))
expect(dayjsUK.format(testFormat4)).toEqual(momentUK.format(testFormat4))
}
})
8 changes: 7 additions & 1 deletion test/locale/keys.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import dayjs from '../../src'

const localeDir = '../../src/locale'
const Locale = []
const localeNameRegex = /\/\/ (.*) \[/

// load all locales from locale dir
fs.readdirSync(path.join(__dirname, localeDir))
.forEach((file) => {
const fPath = path.join(__dirname, localeDir, file)
Locale.push({
name: file,
// eslint-disable-next-line import/no-dynamic-require, global-require
content: require(path.join(__dirname, localeDir, file)).default
content: require(fPath).default,
file: fs.readFileSync(fPath, 'utf-8')
})
})

Expand All @@ -31,6 +34,9 @@ Locale.forEach((locale) => {
yearStart,
meridiem
} = locale.content
// comments required
const commentsMatchResult = locale.file.match(localeNameRegex)
expect(commentsMatchResult[1]).not.toBeUndefined()

expect(name).toEqual(locale.name.replace('.js', ''))
expect(weekdays).toEqual(expect.any(Array))
Expand Down
18 changes: 18 additions & 0 deletions test/locale/lt.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import moment from 'moment'
import dayjs from '../../src'
import '../../src/locale/lt'

it('Format month with locale function', () => {
for (let i = 0; i <= 7; i += 1) {
const dayjsUK = dayjs().locale('lt').add(i, 'day')
const momentUK = moment().locale('lt').add(i, 'day')
const testFormat1 = 'DD MMMM YYYY MMM'
const testFormat2 = 'dddd, MMMM D YYYY'
const testFormat3 = 'MMMM'
const testFormat4 = 'MMM'
expect(dayjsUK.format(testFormat1)).toEqual(momentUK.format(testFormat1))
expect(dayjsUK.format(testFormat2)).toEqual(momentUK.format(testFormat2))
expect(dayjsUK.format(testFormat3)).toEqual(momentUK.format(testFormat3))
expect(dayjsUK.format(testFormat4)).toEqual(momentUK.format(testFormat4))
}
})
15 changes: 15 additions & 0 deletions test/locale/pl.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,21 @@ afterEach(() => {
MockDate.reset()
})

it('Format month with locale function', () => {
for (let i = 0; i <= 7; i += 1) {
const dayjsUK = dayjs().locale('pl').add(i, 'day')
const momentUK = moment().locale('pl').add(i, 'day')
const testFormat1 = 'DD MMMM YYYY MMM'
const testFormat2 = 'dddd, MMMM D YYYY'
const testFormat3 = 'MMMM'
const testFormat4 = 'MMM'
expect(dayjsUK.format(testFormat1)).toEqual(momentUK.format(testFormat1))
expect(dayjsUK.format(testFormat2)).toEqual(momentUK.format(testFormat2))
expect(dayjsUK.format(testFormat3)).toEqual(momentUK.format(testFormat3))
expect(dayjsUK.format(testFormat4)).toEqual(momentUK.format(testFormat4))
}
})

it('RelativeTime: Time from X', () => {
const T = [
[44.4, 'second'], // a few seconds
Expand Down
Loading

0 comments on commit 8b4fc53

Please sign in to comment.