local_time 2.1.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 02425f459bf86821d0c3edab8e84476a55f6b928b521930b0fce12928e41a3e9
4
- data.tar.gz: de41c8acfee651165b14b14e50df09bd4101b980c3789affb626fa3585ff2331
3
+ metadata.gz: 16472bce5a32a57abc8ccd393148ce0d484c45ab64613426c20345529b34e1bb
4
+ data.tar.gz: 12a94969e30573c97fb7483fee71ad21b0f4e97b58fa0588704a02c9c37b2802
5
5
  SHA512:
6
- metadata.gz: bfa2536cb9ca2a0a3bde70c9eee7ea12a85bd022cc819394fef2d77df6acd3f9a927b3ba38110498cb812f2f8959c1cc0f4c8bcbbc82fb6a7f1685417854eeca
7
- data.tar.gz: 66d6fce6ce42a63e83fa0bc9b7bb652ca17dae9f398c58f26684830a24ff7a62266f6e01d3171d22a0b81fcf4ac44a92989d43ae71de9847769f35612bc5565d
6
+ metadata.gz: 6b2d17fb1670ec4eb2ccc62d66ea98e075ad4a91739c7053c30c07bb89a3f0c84abf19da605ddd45760a1b854b76c9cbe89118bc22974a9265dd25f490bc3ee1
7
+ data.tar.gz: b7f22fe3958a23c76e342106eb0defd03cc63e12692d828968c6c5b67ff37149d8be6427e8d21e506c07290eb4c2994c3569fff92d443ff2d75ed5cebbc2333b
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2018 Javan Makhmali, Basecamp
1
+ Copyright 2024 Javan Makhmali, Basecamp
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -4,14 +4,23 @@ Local Time makes it easy to display times and dates to users in their local time
4
4
 
5
5
  ## Installation
6
6
 
7
- 1. Add `gem 'local_time'` to your Gemfile.
8
- 2. Include `local-time.js` in your application's JavaScript bundle.
7
+ ### Importmaps
8
+ 1. Add `gem "local_time"` to your Gemfile.
9
+ 2. Run `bundle install`
10
+ 3. Run `bin/importmap pin local-time` to add the [local-time npm package](https://www.npmjs.com/package/local-time)
11
+ 4. Add this to `app/javascript/application.js`
9
12
 
10
- Using the asset pipeline:
11
13
  ```js
12
- //= require local-time
14
+ import LocalTime from "local-time"
15
+ LocalTime.start()
13
16
  ```
14
- Using the [local-time npm package](https://www.npmjs.com/package/local-time):
17
+
18
+ ### Webpacker
19
+ 1. Add `gem "local_time"` to your Gemfile.
20
+ 2. Run `bundle install`
21
+ 3. Run `yarn add local-time`
22
+ 4. Add this to `app/javascript/packs/application.js`
23
+
15
24
  ```js
16
25
  import LocalTime from "local-time"
17
26
  LocalTime.start()
@@ -78,7 +87,9 @@ To use a strftime format already defined in your app, pass a symbol as the forma
78
87
  <%= local_time(date, :long) %>
79
88
  ```
80
89
 
81
- `I18n.t("time.formats.#{format}")`, `I18n.t("date.formats.#{format}")`, `Time::DATE_FORMATS[format]`, and `Date::DATE_FORMATS[format]` will be scanned (in that order) for your format.
90
+ When using the `local_time` helper `I18n.t("time.formats.#{format}")`, `I18n.t("date.formats.#{format}")`, `Time::DATE_FORMATS[format]`, and `Date::DATE_FORMATS[format]` will be scanned (in that order) for your format.
91
+
92
+ When using the `local_date` helper, `I18n.t("date.formats.#{format}")`, `I18n.t("time.formats.#{format}")`, `Date::DATE_FORMATS[format]`, and `Time::DATE_FORMATS[format]` will be scanned (in that order) for your format.
82
93
 
83
94
  Note: The included strftime JavaScript implementation is not 100% complete. It supports the following directives: `%a %A %b %B %c %d %e %H %I %l %m %M %p %P %S %w %y %Y %Z`
84
95
 
@@ -140,8 +151,31 @@ LocalTime.config.i18n["es"] = {
140
151
  LocalTime.config.locale = "es"
141
152
  ```
142
153
 
143
- ---
154
+ **24-hour time formatting**
155
+ Local Time supports 24-hour time formats out of the box.
156
+
157
+ To use this feature, configure the library to favor `data-format24` over `data-format` attributes:
158
+
159
+ ```js
160
+ LocalTime.config.useFormat24 = true
161
+ ```
162
+
163
+ The library will now default to using the `data-format24` attribute on `<time>` elements for formatting.
164
+ But it will still fall back to `data-format` if `data-format24` is not provided.
165
+
166
+ The included Rails helpers will automatically look for 24h variants of named formats.
167
+ They will search for `#{name}_24h` in [the same places](#time-and-date-helpers) the regular name is looked up.
168
+
169
+ This is an example of what your app configuration might look like:
170
+
171
+ ```ruby
172
+ Time::DATE_FORMATS[:simple] = "%-l:%M%P"
173
+ Time::DATE_FORMATS[:simple_24h] = "%H:%M"
174
+ ```
175
+
176
+ When `:type` is set to `time-ago`, the format is obtained from the `I18n` [configuration](#configuration).
144
177
 
145
- [![Build Status](https://travis-ci.org/basecamp/local_time.svg?branch=master)](https://travis-ci.org/basecamp/local_time)
178
+ In practice, you might set `config.useFormat24` to `true` or `false` depending on the current user's configuration, before rendering any `<time>` elements.
146
179
 
147
- [![Sauce Test Status](https://saucelabs.com/browser-matrix/basecamp_local_time.svg)](https://saucelabs.com/u/basecamp_local_time)
180
+ ## Contributing
181
+ Please read [CONTRIBUTING.md](./CONTRIBUTING.md).
@@ -0,0 +1 @@
1
+ var t;t={config:{},run:function(){return this.getController().processElements()},process:function(...t){var e,r,a;for(r=0,a=t.length;r<a;r++)e=t[r],this.getController().processElement(e);return t.length},getController:function(){return null!=this.controller?this.controller:this.controller=new t.Controller}};var e,r,a,n,s,i,o,u,l,c,d,m,h,f,g,p,S,v,y,T,b,M,D,w,E,I,C,N,A,O,$,F,Y,k,W,L=t;L.config.useFormat24=!1,L.config.i18n={en:{date:{dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbrDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbrMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],yesterday:"yesterday",today:"today",tomorrow:"tomorrow",on:"on {date}",formats:{default:"%b %e, %Y",thisYear:"%b %e"}},time:{am:"am",pm:"pm",singular:"a {time}",singularAn:"an {time}",elapsed:"{time} ago",second:"second",seconds:"seconds",minute:"minute",minutes:"minutes",hour:"hour",hours:"hours",formats:{default:"%l:%M%P",default_24h:"%H:%M"}},datetime:{at:"{date} at {time}",formats:{default:"%B %e, %Y at %l:%M%P %Z",default_24h:"%B %e, %Y at %H:%M %Z"}}}},L.config.locale="en",L.config.defaultLocale="en",L.config.timerInterval=6e4,a=!isNaN(Date.parse("2011-01-01T12:00:00-05:00")),L.parseDate=function(t){return t=t.toString(),a||(t=r(t)),new Date(Date.parse(t))},e=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/,r=function(t){var r,a,n,s,i,o,u,l,c,d;if(s=t.match(e))return[r,c,o,a,n,i,l,d]=s,"Z"!==d&&(u=d.replace(":","")),`${c}/${o}/${a} ${n}:${i}:${l} GMT${[u]}`},L.elementMatchesSelector=(n=document.documentElement,s=null!=(i=null!=(o=null!=(u=null!=(l=n.matches)?l:n.matchesSelector)?u:n.webkitMatchesSelector)?o:n.mozMatchesSelector)?i:n.msMatchesSelector,function(t,e){if((null!=t?t.nodeType:void 0)===Node.ELEMENT_NODE)return s.call(t,e)}),({config:c}=L),({i18n:m}=c),L.getI18nValue=function(t="",{locale:e}={locale:c.locale}){var r;return null!=(r=d(m[e],t))?r:e!==c.defaultLocale?L.getI18nValue(t,{locale:c.defaultLocale}):void 0},L.translate=function(t,e={},r){var a,n,s;for(a in s=L.getI18nValue(t,r),e)n=e[a],s=s.replace(`{${a}}`,n);return s},d=function(t,e){var r,a,n,s,i;for(i=t,r=0,n=(s=e.split(".")).length;r<n;r++){if(null==i[a=s[r]])return null;i=i[a]}return i},({getI18nValue:f,translate:M}=L),b="function"==typeof("undefined"!=typeof Intl&&null!==Intl?Intl.DateTimeFormat:void 0),g={"Central European Standard Time":"CET","Central European Summer Time":"CEST","China Standard Time":"CST","Israel Daylight Time":"IDT","Israel Standard Time":"IST","Moscow Standard Time":"MSK","Philippine Standard Time":"PHT","Singapore Standard Time":"SGT","Western Indonesia Time":"WIB"},L.knownEdgeCaseTimeZones=g,L.strftime=T=function(t,e){var r,a,n,s,i,o,u;return a=t.getDay(),r=t.getDate(),i=t.getMonth(),u=t.getFullYear(),n=t.getHours(),s=t.getMinutes(),o=t.getSeconds(),e.replace(/%(-?)([%aAbBcdeHIlmMpPSwyYZ])/g,(function(e,l,c){switch(c){case"%":return"%";case"a":return f("date.abbrDayNames")[a];case"A":return f("date.dayNames")[a];case"b":return f("date.abbrMonthNames")[i];case"B":return f("date.monthNames")[i];case"c":return t.toString();case"d":return p(r,l);case"e":return r;case"H":return p(n,l);case"I":return p(T(t,"%l"),l);case"l":return 0===n||12===n?12:(n+12)%12;case"m":return p(i+1,l);case"M":return p(s,l);case"p":return M("time."+(n>11?"pm":"am")).toUpperCase();case"P":return M("time."+(n>11?"pm":"am"));case"S":return p(o,l);case"w":return a;case"y":return p(u%100,l);case"Y":return u;case"Z":return S(t)}}))},p=function(t,e){return"-"===e?t:`0${t}`.slice(-2)},S=function(t){var e,r,a;return(r=h(t))?g[r]:(a=y(t,{allowGMT:!1}))||(a=v(t))?a:(e=y(t,{allowGMT:!0}))?e:""},h=function(t){return Object.keys(g).find((function(e){return b?new Date(t).toLocaleString("en-US",{timeZoneName:"long"}).includes(e):t.toString().includes(e)}))},y=function(t,{allowGMT:e}){var r;if(b&&(r=new Date(t).toLocaleString("en-US",{timeZoneName:"short"}).split(" ").pop(),e||!r.includes("GMT")))return r},v=function(t){var e,r,a,n,s;return(e=null!=(r=(s=t.toString()).match(/\(([\w\s]+)\)$/))?r[1]:void 0)?/\s/.test(e)?e.match(/\b(\w)/g).join(""):e:(e=null!=(a=s.match(/(\w{3,4})\s\d{4}$/))?a[1]:void 0)||(e=null!=(n=s.match(/(UTC[\+\-]\d+)/))?n[1]:void 0)?e:void 0},L.CalendarDate=class{static fromDate(t){return new this(t.getFullYear(),t.getMonth()+1,t.getDate())}static today(){return this.fromDate(new Date)}constructor(t,e,r){this.date=new Date(Date.UTC(t,e-1)),this.date.setUTCDate(r),this.year=this.date.getUTCFullYear(),this.month=this.date.getUTCMonth()+1,this.day=this.date.getUTCDate(),this.value=this.date.getTime()}equals(t){return(null!=t?t.value:void 0)===this.value}is(t){return this.equals(t)}isToday(){return this.is(this.constructor.today())}occursOnSameYearAs(t){return this.year===(null!=t?t.year:void 0)}occursThisYear(){return this.occursOnSameYearAs(this.constructor.today())}daysSince(t){if(t)return(this.date-t.date)/864e5}daysPassed(){return this.constructor.today().daysSince(this)}},({strftime:E,translate:I,getI18nValue:w,config:D}=L),L.RelativeTime=class{constructor(t){this.date=t,this.calendarDate=L.CalendarDate.fromDate(this.date)}toString(){var t,e;return(e=this.toTimeElapsedString())?I("time.elapsed",{time:e}):(t=this.toWeekdayString())?(e=this.toTimeString(),I("datetime.at",{date:t,time:e})):I("date.on",{date:this.toDateString()})}toTimeOrDateString(){return this.calendarDate.isToday()?this.toTimeString():this.toDateString()}toTimeElapsedString(){var t,e,r,a,n;return r=(new Date).getTime()-this.date.getTime(),a=Math.round(r/1e3),e=Math.round(a/60),t=Math.round(e/60),r<0?null:a<10?(n=I("time.second"),I("time.singular",{time:n})):a<45?`${a} ${I("time.seconds")}`:a<90?(n=I("time.minute"),I("time.singular",{time:n})):e<45?`${e} ${I("time.minutes")}`:e<90?(n=I("time.hour"),I("time.singularAn",{time:n})):t<24?`${t} ${I("time.hours")}`:""}toWeekdayString(){switch(this.calendarDate.daysPassed()){case 0:return I("date.today");case 1:return I("date.yesterday");case-1:return I("date.tomorrow");case 2:case 3:case 4:case 5:case 6:return E(this.date,"%A");default:return""}}toDateString(){var t;return t=this.calendarDate.occursThisYear()?w("date.formats.thisYear"):w("date.formats.default"),E(this.date,t)}toTimeString(){var t;return t=D.useFormat24?"default_24h":"default",E(this.date,w(`time.formats.${t}`))}},({elementMatchesSelector:C}=L),L.PageObserver=class{constructor(t,e){this.processMutations=this.processMutations.bind(this),this.processInsertion=this.processInsertion.bind(this),this.selector=t,this.callback=e}start(){if(!this.started)return this.observeWithMutationObserver()||this.observeWithMutationEvent(),this.started=!0}observeWithMutationObserver(){if("undefined"!=typeof MutationObserver&&null!==MutationObserver)return new MutationObserver(this.processMutations).observe(document.documentElement,{childList:!0,subtree:!0}),!0}observeWithMutationEvent(){return addEventListener("DOMNodeInserted",this.processInsertion,!1),!0}findSignificantElements(t){var e;return e=[],(null!=t?t.nodeType:void 0)===Node.ELEMENT_NODE&&(C(t,this.selector)&&e.push(t),e.push(...t.querySelectorAll(this.selector))),e}processMutations(t){var e,r,a,n,s,i,o,u;for(e=[],r=0,n=t.length;r<n;r++)if("childList"===(i=t[r]).type)for(a=0,s=(u=i.addedNodes).length;a<s;a++)o=u[a],e.push(...this.findSignificantElements(o));return this.notify(e)}processInsertion(t){var e;return e=this.findSignificantElements(t.target),this.notify(e)}notify(t){if(null!=t?t.length:void 0)return"function"==typeof this.callback?this.callback(t):void 0}},({parseDate:O,strftime:$,getI18nValue:A,config:N}=L),L.Controller=function(){var t,e,r,a;return t="time[data-local]:not([data-localized])",e=function(t){return t.setAttribute("data-localized","")},r=function(t){return t.setAttribute("data-processed-at",(new Date).toISOString())},a=function(t){return new L.RelativeTime(t)},class{constructor(){this.processElements=this.processElements.bind(this),this.pageObserver=new L.PageObserver(t,this.processElements)}start(){if(!this.started)return this.processElements(),this.startTimer(),this.pageObserver.start(),this.started=!0}startTimer(){var t;if(t=N.timerInterval)return null!=this.timer?this.timer:this.timer=setInterval(this.processElements,t)}processElements(e=document.querySelectorAll(t)){var r,a,n;for(a=0,n=e.length;a<n;a++)r=e[a],this.processElement(r);return e.length}processElement(t){var n,s,i,o,u,l;if(n=t.getAttribute("datetime"),i=t.getAttribute("data-local"),s=N.useFormat24&&t.getAttribute("data-format24")||t.getAttribute("data-format"),o=O(n),!isNaN(o))return t.hasAttribute("title")||(l=N.useFormat24?"default_24h":"default",u=$(o,A(`datetime.formats.${l}`)),t.setAttribute("title",u)),r(t),t.textContent=function(){switch(i){case"time":return e(t),$(o,s);case"date":return e(t),a(o).toDateString();case"time-ago":return a(o).toString();case"time-or-date":return a(o).toTimeOrDateString();case"weekday":return a(o).toWeekdayString();case"weekday-or-date":return a(o).toWeekdayString()||a(o).toDateString()}}()}}}.call(window),W=!1,F=function(){return document.attachEvent?"complete"===document.readyState:"loading"!==document.readyState},Y=function(t){var e;return null!=(e="function"==typeof requestAnimationFrame?requestAnimationFrame(t):void 0)?e:setTimeout(t,17)},k=function(){return L.getController().start()},L.start=function(){return W?L.run():(W=!0,"undefined"!=typeof MutationObserver&&null!==MutationObserver||F()?k():Y(k))},L.processing=function(){return L.getController().started},window.LocalTime===L&&L.start();export{L as default};
@@ -0,0 +1 @@
1
+ !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).LocalTime=t()}(this,(function(){"use strict";var e;e={config:{},run:function(){return this.getController().processElements()},process:function(...e){var t,r,n;for(r=0,n=e.length;r<n;r++)t=e[r],this.getController().processElement(t);return e.length},getController:function(){return null!=this.controller?this.controller:this.controller=new e.Controller}};var t,r,n,a,i,s,o,u,l,c,d,m,h,f,g,p,y,S,v,T,b,M,D,w,E,I,C,N,A,O,$,F,Y,k,L,W=e;return W.config.useFormat24=!1,W.config.i18n={en:{date:{dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbrDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbrMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],yesterday:"yesterday",today:"today",tomorrow:"tomorrow",on:"on {date}",formats:{default:"%b %e, %Y",thisYear:"%b %e"}},time:{am:"am",pm:"pm",singular:"a {time}",singularAn:"an {time}",elapsed:"{time} ago",second:"second",seconds:"seconds",minute:"minute",minutes:"minutes",hour:"hour",hours:"hours",formats:{default:"%l:%M%P",default_24h:"%H:%M"}},datetime:{at:"{date} at {time}",formats:{default:"%B %e, %Y at %l:%M%P %Z",default_24h:"%B %e, %Y at %H:%M %Z"}}}},W.config.locale="en",W.config.defaultLocale="en",W.config.timerInterval=6e4,n=!isNaN(Date.parse("2011-01-01T12:00:00-05:00")),W.parseDate=function(e){return e=e.toString(),n||(e=r(e)),new Date(Date.parse(e))},t=/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/,r=function(e){var r,n,a,i,s,o,u,l,c,d;if(i=e.match(t))return[r,c,o,n,a,s,l,d]=i,"Z"!==d&&(u=d.replace(":","")),`${c}/${o}/${n} ${a}:${s}:${l} GMT${[u]}`},W.elementMatchesSelector=(a=document.documentElement,i=null!=(s=null!=(o=null!=(u=null!=(l=a.matches)?l:a.matchesSelector)?u:a.webkitMatchesSelector)?o:a.mozMatchesSelector)?s:a.msMatchesSelector,function(e,t){if((null!=e?e.nodeType:void 0)===Node.ELEMENT_NODE)return i.call(e,t)}),({config:c}=W),({i18n:m}=c),W.getI18nValue=function(e="",{locale:t}={locale:c.locale}){var r;return null!=(r=d(m[t],e))?r:t!==c.defaultLocale?W.getI18nValue(e,{locale:c.defaultLocale}):void 0},W.translate=function(e,t={},r){var n,a,i;for(n in i=W.getI18nValue(e,r),t)a=t[n],i=i.replace(`{${n}}`,a);return i},d=function(e,t){var r,n,a,i,s;for(s=e,r=0,a=(i=t.split(".")).length;r<a;r++){if(null==s[n=i[r]])return null;s=s[n]}return s},({getI18nValue:f,translate:M}=W),b="function"==typeof("undefined"!=typeof Intl&&null!==Intl?Intl.DateTimeFormat:void 0),g={"Central European Standard Time":"CET","Central European Summer Time":"CEST","China Standard Time":"CST","Israel Daylight Time":"IDT","Israel Standard Time":"IST","Moscow Standard Time":"MSK","Philippine Standard Time":"PHT","Singapore Standard Time":"SGT","Western Indonesia Time":"WIB"},W.knownEdgeCaseTimeZones=g,W.strftime=T=function(e,t){var r,n,a,i,s,o,u;return n=e.getDay(),r=e.getDate(),s=e.getMonth(),u=e.getFullYear(),a=e.getHours(),i=e.getMinutes(),o=e.getSeconds(),t.replace(/%(-?)([%aAbBcdeHIlmMpPSwyYZ])/g,(function(t,l,c){switch(c){case"%":return"%";case"a":return f("date.abbrDayNames")[n];case"A":return f("date.dayNames")[n];case"b":return f("date.abbrMonthNames")[s];case"B":return f("date.monthNames")[s];case"c":return e.toString();case"d":return p(r,l);case"e":return r;case"H":return p(a,l);case"I":return p(T(e,"%l"),l);case"l":return 0===a||12===a?12:(a+12)%12;case"m":return p(s+1,l);case"M":return p(i,l);case"p":return M("time."+(a>11?"pm":"am")).toUpperCase();case"P":return M("time."+(a>11?"pm":"am"));case"S":return p(o,l);case"w":return n;case"y":return p(u%100,l);case"Y":return u;case"Z":return y(e)}}))},p=function(e,t){return"-"===t?e:`0${e}`.slice(-2)},y=function(e){var t,r,n;return(r=h(e))?g[r]:(n=v(e,{allowGMT:!1}))||(n=S(e))?n:(t=v(e,{allowGMT:!0}))?t:""},h=function(e){return Object.keys(g).find((function(t){return b?new Date(e).toLocaleString("en-US",{timeZoneName:"long"}).includes(t):e.toString().includes(t)}))},v=function(e,{allowGMT:t}){var r;if(b&&(r=new Date(e).toLocaleString("en-US",{timeZoneName:"short"}).split(" ").pop(),t||!r.includes("GMT")))return r},S=function(e){var t,r,n,a,i;return(t=null!=(r=(i=e.toString()).match(/\(([\w\s]+)\)$/))?r[1]:void 0)?/\s/.test(t)?t.match(/\b(\w)/g).join(""):t:(t=null!=(n=i.match(/(\w{3,4})\s\d{4}$/))?n[1]:void 0)||(t=null!=(a=i.match(/(UTC[\+\-]\d+)/))?a[1]:void 0)?t:void 0},W.CalendarDate=class{static fromDate(e){return new this(e.getFullYear(),e.getMonth()+1,e.getDate())}static today(){return this.fromDate(new Date)}constructor(e,t,r){this.date=new Date(Date.UTC(e,t-1)),this.date.setUTCDate(r),this.year=this.date.getUTCFullYear(),this.month=this.date.getUTCMonth()+1,this.day=this.date.getUTCDate(),this.value=this.date.getTime()}equals(e){return(null!=e?e.value:void 0)===this.value}is(e){return this.equals(e)}isToday(){return this.is(this.constructor.today())}occursOnSameYearAs(e){return this.year===(null!=e?e.year:void 0)}occursThisYear(){return this.occursOnSameYearAs(this.constructor.today())}daysSince(e){if(e)return(this.date-e.date)/864e5}daysPassed(){return this.constructor.today().daysSince(this)}},({strftime:E,translate:I,getI18nValue:w,config:D}=W),W.RelativeTime=class{constructor(e){this.date=e,this.calendarDate=W.CalendarDate.fromDate(this.date)}toString(){var e,t;return(t=this.toTimeElapsedString())?I("time.elapsed",{time:t}):(e=this.toWeekdayString())?(t=this.toTimeString(),I("datetime.at",{date:e,time:t})):I("date.on",{date:this.toDateString()})}toTimeOrDateString(){return this.calendarDate.isToday()?this.toTimeString():this.toDateString()}toTimeElapsedString(){var e,t,r,n,a;return r=(new Date).getTime()-this.date.getTime(),n=Math.round(r/1e3),t=Math.round(n/60),e=Math.round(t/60),r<0?null:n<10?(a=I("time.second"),I("time.singular",{time:a})):n<45?`${n} ${I("time.seconds")}`:n<90?(a=I("time.minute"),I("time.singular",{time:a})):t<45?`${t} ${I("time.minutes")}`:t<90?(a=I("time.hour"),I("time.singularAn",{time:a})):e<24?`${e} ${I("time.hours")}`:""}toWeekdayString(){switch(this.calendarDate.daysPassed()){case 0:return I("date.today");case 1:return I("date.yesterday");case-1:return I("date.tomorrow");case 2:case 3:case 4:case 5:case 6:return E(this.date,"%A");default:return""}}toDateString(){var e;return e=this.calendarDate.occursThisYear()?w("date.formats.thisYear"):w("date.formats.default"),E(this.date,e)}toTimeString(){var e;return e=D.useFormat24?"default_24h":"default",E(this.date,w(`time.formats.${e}`))}},({elementMatchesSelector:C}=W),W.PageObserver=class{constructor(e,t){this.processMutations=this.processMutations.bind(this),this.processInsertion=this.processInsertion.bind(this),this.selector=e,this.callback=t}start(){if(!this.started)return this.observeWithMutationObserver()||this.observeWithMutationEvent(),this.started=!0}observeWithMutationObserver(){if("undefined"!=typeof MutationObserver&&null!==MutationObserver)return new MutationObserver(this.processMutations).observe(document.documentElement,{childList:!0,subtree:!0}),!0}observeWithMutationEvent(){return addEventListener("DOMNodeInserted",this.processInsertion,!1),!0}findSignificantElements(e){var t;return t=[],(null!=e?e.nodeType:void 0)===Node.ELEMENT_NODE&&(C(e,this.selector)&&t.push(e),t.push(...e.querySelectorAll(this.selector))),t}processMutations(e){var t,r,n,a,i,s,o,u;for(t=[],r=0,a=e.length;r<a;r++)if("childList"===(s=e[r]).type)for(n=0,i=(u=s.addedNodes).length;n<i;n++)o=u[n],t.push(...this.findSignificantElements(o));return this.notify(t)}processInsertion(e){var t;return t=this.findSignificantElements(e.target),this.notify(t)}notify(e){if(null!=e?e.length:void 0)return"function"==typeof this.callback?this.callback(e):void 0}},({parseDate:O,strftime:$,getI18nValue:A,config:N}=W),W.Controller=function(){var e,t,r,n;return e="time[data-local]:not([data-localized])",t=function(e){return e.setAttribute("data-localized","")},r=function(e){return e.setAttribute("data-processed-at",(new Date).toISOString())},n=function(e){return new W.RelativeTime(e)},class{constructor(){this.processElements=this.processElements.bind(this),this.pageObserver=new W.PageObserver(e,this.processElements)}start(){if(!this.started)return this.processElements(),this.startTimer(),this.pageObserver.start(),this.started=!0}startTimer(){var e;if(e=N.timerInterval)return null!=this.timer?this.timer:this.timer=setInterval(this.processElements,e)}processElements(t=document.querySelectorAll(e)){var r,n,a;for(n=0,a=t.length;n<a;n++)r=t[n],this.processElement(r);return t.length}processElement(e){var a,i,s,o,u,l;if(a=e.getAttribute("datetime"),s=e.getAttribute("data-local"),i=N.useFormat24&&e.getAttribute("data-format24")||e.getAttribute("data-format"),o=O(a),!isNaN(o))return e.hasAttribute("title")||(l=N.useFormat24?"default_24h":"default",u=$(o,A(`datetime.formats.${l}`)),e.setAttribute("title",u)),r(e),e.textContent=function(){switch(s){case"time":return t(e),$(o,i);case"date":return t(e),n(o).toDateString();case"time-ago":return n(o).toString();case"time-or-date":return n(o).toTimeOrDateString();case"weekday":return n(o).toWeekdayString();case"weekday-or-date":return n(o).toWeekdayString()||n(o).toDateString()}}()}}}.call(window),L=!1,F=function(){return document.attachEvent?"complete"===document.readyState:"loading"!==document.readyState},Y=function(e){var t;return null!=(t="function"==typeof requestAnimationFrame?requestAnimationFrame(e):void 0)?t:setTimeout(e,17)},k=function(){return W.getController().start()},W.start=function(){return L?W.run():(L=!0,"undefined"!=typeof MutationObserver&&null!==MutationObserver||F()?k():Y(k))},W.processing=function(){return W.getController().started},window.LocalTime===W&&W.start(),W}));
@@ -2,19 +2,19 @@ module LocalTimeHelper
2
2
  def local_time(time, options = nil)
3
3
  time = utc_time(time)
4
4
 
5
- options, format = extract_options_and_value(options, :format)
6
- format = find_time_format(format)
5
+ options, format12 = extract_options_and_value(options, :format)
6
+ format12, format24 = find_12h_and_24h_formats(format12)
7
7
 
8
8
  options[:data] ||= {}
9
- options[:data].merge! local: :time, format: format
9
+ options[:data].merge! local: :time, format: format12, format24: format24
10
10
 
11
- time_tag time, time.strftime(format), options
11
+ time_tag time, time.strftime(format12), options
12
12
  end
13
13
 
14
14
  def local_date(time, options = nil)
15
15
  options, format = extract_options_and_value(options, :format)
16
- options[:format] = format || LocalTime.default_date_format
17
- local_time time, options
16
+ format, _ = find_12h_and_24h_formats(format, prefer: :date)
17
+ local_time time, options.merge(format: format)
18
18
  end
19
19
 
20
20
  def local_relative_time(time, options = nil)
@@ -29,7 +29,7 @@ module LocalTimeHelper
29
29
 
30
30
  def local_time_ago(time, options = nil)
31
31
  options, * = extract_options_and_value(options, :type)
32
- options[:type] = 'time-ago'
32
+ options[:type] = "time-ago"
33
33
  local_relative_time time, options
34
34
  end
35
35
 
@@ -42,20 +42,6 @@ module LocalTimeHelper
42
42
  end
43
43
 
44
44
  private
45
- def find_time_format(format)
46
- if format.is_a?(Symbol)
47
- if (i18n_format = I18n.t("time.formats.#{format}", default: [:"date.formats.#{format}", ''])).present?
48
- i18n_format
49
- elsif (date_format = Time::DATE_FORMATS[format] || Date::DATE_FORMATS[format])
50
- date_format.is_a?(Proc) ? LocalTime.default_time_format : date_format
51
- else
52
- LocalTime.default_time_format
53
- end
54
- else
55
- format.presence || LocalTime.default_time_format
56
- end
57
- end
58
-
59
45
  def extract_options_and_value(options, value_key = nil)
60
46
  case options
61
47
  when Hash
@@ -67,4 +53,69 @@ module LocalTimeHelper
67
53
  [ {}, options ]
68
54
  end
69
55
  end
56
+
57
+ def find_12h_and_24h_formats(format12, prefer: :time)
58
+ if format12.is_a?(Symbol)
59
+ find_time_formats_by_name(format12, prefer: prefer)
60
+ else
61
+ [ format12.presence || default_time_format(prefer), nil ]
62
+ end
63
+ end
64
+
65
+ def find_time_formats_by_name(name, prefer:)
66
+ if use_i18n_time_formats?(name)
67
+ find_i18_time_formats(name, prefer: prefer)
68
+ elsif use_ruby_time_formats?(name)
69
+ find_ruby_time_formats(name, prefer: prefer)
70
+ else
71
+ [ default_time_format(prefer), nil ]
72
+ end
73
+ end
74
+
75
+ def default_time_format(prefer = :time)
76
+ if prefer == :time
77
+ LocalTime.default_time_format
78
+ else
79
+ LocalTime.default_date_format
80
+ end
81
+ end
82
+
83
+ def use_i18n_time_formats?(name)
84
+ i18n_time_or_date_format(name).present?
85
+ end
86
+
87
+ def i18n_time_or_date_format(name, prefer: :time)
88
+ if prefer == :time
89
+ I18n.t("time.formats.#{name}", default: [ :"date.formats.#{name}", "" ]).presence
90
+ else
91
+ I18n.t("date.formats.#{name}", default: [ :"time.formats.#{name}", "" ]).presence
92
+ end
93
+ end
94
+
95
+ def find_i18_time_formats(name, prefer:)
96
+ [ i18n_time_or_date_format(name, prefer: prefer),
97
+ i18n_time_or_date_format("#{name}_24h", prefer: prefer) ]
98
+ end
99
+
100
+ def use_ruby_time_formats?(name)
101
+ ruby_time_or_date_format(name).present?
102
+ end
103
+
104
+ def ruby_time_or_date_format(name, prefer: :time)
105
+ if prefer == :time
106
+ Time::DATE_FORMATS.with_indifferent_access[name] || Date::DATE_FORMATS.with_indifferent_access[name]
107
+ else
108
+ Date::DATE_FORMATS.with_indifferent_access[name] || Time::DATE_FORMATS.with_indifferent_access[name]
109
+ end
110
+ end
111
+
112
+ def find_ruby_time_formats(name, prefer:)
113
+ format12 = ruby_time_or_date_format(name, prefer: prefer)
114
+
115
+ if format12.is_a?(Proc)
116
+ [ default_time_format(prefer), nil ]
117
+ else
118
+ [ format12, ruby_time_or_date_format("#{name}_24h", prefer: prefer) ]
119
+ end
120
+ end
70
121
  end
@@ -0,0 +1,3 @@
1
+ module LocalTime
2
+ VERSION = "3.0.2"
3
+ end
@@ -1,11 +1,12 @@
1
- require 'rails'
2
- require 'action_view'
3
- require 'rails-dom-testing'
1
+ require "rails"
2
+ require "active_support/all"
3
+ require "action_view"
4
+ require "rails-dom-testing"
4
5
 
5
- require 'local_time'
6
- require_relative '../../app/helpers/local_time_helper'
6
+ require "local_time"
7
+ require_relative "../../app/helpers/local_time_helper"
7
8
 
8
- require 'minitest/autorun'
9
+ require "minitest/autorun"
9
10
  begin
10
11
  # 2.0.0
11
12
  class TestCase < MiniTest::Test; end
@@ -26,10 +27,14 @@ class LocalTimeHelperTest < TestCase
26
27
  @original_zone = Time.zone
27
28
  Time.zone = ActiveSupport::TimeZone["Central Time (US & Canada)"]
28
29
  I18n.backend.store_translations(:en, {
29
- time: { formats: { simple_time: "%b %e" } },
30
- date: { formats: { simple_date: "%b %e" } } })
31
- Time::DATE_FORMATS[:time_formats_simple_time] = '%b %e'
32
- Date::DATE_FORMATS[:date_formats_simple_date] = '%b %e'
30
+ time: { formats: { simple_time: "%-l:%M%P", simple_time_24h: "%H:%M", time_with_context: "%b %e, %-l:%M%P", ambiguous_format: "%Y-%m-%d %H:%M:%S" } },
31
+ date: { formats: { simple_date: "%b %e", ambiguous_format: "%Y-%m-%d" } } })
32
+ Time::DATE_FORMATS[:time_formats_simple_time] = "%-l:%M%P"
33
+ Time::DATE_FORMATS[:time_formats_simple_time_24h] = "%H:%M"
34
+ Time::DATE_FORMATS[:time_formats_time_with_context] = "%b %e, %-l:%M%P"
35
+ Time::DATE_FORMATS[:ruby_ambiguous_format] = "%Y-%m-%d %H:%M:%S"
36
+ Date::DATE_FORMATS[:ruby_ambiguous_format] = "%Y-%m-%d"
37
+ Date::DATE_FORMATS[:date_formats_simple_date] = "%b %e"
33
38
 
34
39
  @date = "2013-11-21"
35
40
  @time = Time.zone.parse(@date)
@@ -61,25 +66,35 @@ class LocalTimeHelperTest < TestCase
61
66
 
62
67
  def test_local_time_with_format
63
68
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
64
- assert_dom_equal expected, local_time(@time, format: '%b %e')
69
+ assert_dom_equal expected, local_time(@time, format: "%b %e")
65
70
  end
66
71
 
67
72
  def test_local_time_with_format_as_string
68
73
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
69
- assert_dom_equal expected, local_time(@time, '%b %e')
74
+ assert_dom_equal expected, local_time(@time, "%b %e")
70
75
  end
71
76
 
72
77
  def test_local_time_with_i18n_format
73
- expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
78
+ expected = %Q(<time data-format="%-l:%M%P" data-format24="%H:%M" data-local="time" datetime="#{@time_js}">6:00am</time>)
74
79
  assert_dom_equal expected, local_time(@time, format: :simple_time)
75
80
  end
76
81
 
77
- def test_local_time_with_date_formats_format
78
- expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
82
+ def test_local_time_with_i18n_format_missing_24h
83
+ expected = %Q(<time data-format="%b %e, %-l:%M%P" data-local="time" datetime="#{@time_js}">Nov 21, 6:00am</time>)
84
+ assert_dom_equal expected, local_time(@time, format: :time_with_context)
85
+ end
86
+
87
+ def test_local_time_with_ruby_format
88
+ expected = %Q(<time data-format="%-l:%M%P" data-format24="%H:%M" data-local="time" datetime="#{@time_js}">6:00am</time>)
79
89
  assert_dom_equal expected, local_time(@time, format: :time_formats_simple_time)
80
90
  end
81
91
 
82
- def test_local_time_with_missing_i18n_and_date_formats_format
92
+ def test_local_time_with_ruby_format_missing_24h
93
+ expected = %Q(<time data-format="%b %e, %-l:%M%P" data-local="time" datetime="#{@time_js}">Nov 21, 6:00am</time>)
94
+ assert_dom_equal expected, local_time(@time, format: :time_formats_time_with_context)
95
+ end
96
+
97
+ def test_local_time_with_missing_i18n_and_ruby_format
83
98
  expected = %Q(<time data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
84
99
  assert_dom_equal expected, local_time(@time, format: :missing_format)
85
100
  end
@@ -92,7 +107,27 @@ class LocalTimeHelperTest < TestCase
92
107
 
93
108
  def test_local_time_with_options
94
109
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}" style="display:none">Nov 21</time>)
95
- assert_dom_equal expected, local_time(@time, format: '%b %e', style: 'display:none')
110
+ assert_dom_equal expected, local_time(@time, format: "%b %e", style: "display:none")
111
+ end
112
+
113
+ def test_local_time_with_ruby_ambiguous_format
114
+ expected = %Q(<time data-format="%Y-%m-%d %H:%M:%S" data-local="time" datetime="#{@time_js}">2013-11-21 06:00:00</time>)
115
+ assert_dom_equal expected, local_time(@time, format: :ruby_ambiguous_format)
116
+ end
117
+
118
+ def test_local_time_with_i18n_ambiguous_format
119
+ expected = %Q(<time data-format="%Y-%m-%d %H:%M:%S" data-local="time" datetime="#{@time_js}">2013-11-21 06:00:00</time>)
120
+ assert_dom_equal expected, local_time(@time, format: :ambiguous_format)
121
+ end
122
+
123
+ def test_local_date_with_ruby_ambiguous_format
124
+ expected = %Q(<time data-format="%Y-%m-%d" data-local="time" datetime="#{@time_js}">2013-11-21</time>)
125
+ assert_dom_equal expected, local_date(@time.to_date, format: :ruby_ambiguous_format)
126
+ end
127
+
128
+ def test_local_date_with_i18n_ambiguous_format
129
+ expected = %Q(<time data-format="%Y-%m-%d" data-local="time" datetime="#{@time_js}">2013-11-21</time>)
130
+ assert_dom_equal expected, local_date(@time.to_date, format: :ambiguous_format)
96
131
  end
97
132
 
98
133
  def test_local_date
@@ -103,12 +138,12 @@ class LocalTimeHelperTest < TestCase
103
138
 
104
139
  def test_local_date_with_format
105
140
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
106
- assert_dom_equal expected, local_date(@time.to_date, format: '%b %e')
141
+ assert_dom_equal expected, local_date(@time.to_date, format: "%b %e")
107
142
  end
108
143
 
109
144
  def test_local_date_with_format_as_string
110
145
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
111
- assert_dom_equal expected, local_date(@time.to_date, '%b %e')
146
+ assert_dom_equal expected, local_date(@time.to_date, "%b %e")
112
147
  end
113
148
 
114
149
  def test_local_date_with_i18n_format
@@ -116,13 +151,13 @@ class LocalTimeHelperTest < TestCase
116
151
  assert_dom_equal expected, local_date(@time.to_date, format: :simple_date)
117
152
  end
118
153
 
119
- def test_local_date_with_date_formats_format
154
+ def test_local_date_with_ruby_format
120
155
  expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
121
156
  assert_dom_equal expected, local_date(@time.to_date, format: :date_formats_simple_date)
122
157
  end
123
158
 
124
- def test_local_date_with_missing_i18n_and_date_formats_format
125
- expected = %Q(<time data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
159
+ def test_local_date_with_missing_i18n_and_ruby_format
160
+ expected = %Q(<time data-format="%B %e, %Y" data-local="time" datetime="#{@time_js}">November 21, 2013</time>)
126
161
  assert_dom_equal expected, local_date(@time.to_date, format: :missing_date_format)
127
162
  end
128
163