From 1fd88c28ef9a851d38d2d6a0420ee686368b0626 Mon Sep 17 00:00:00 2001 From: Holger Brunn Date: Mon, 6 Oct 2014 22:01:55 +0200 Subject: [PATCH] [ADD] web_pytz --- web_pytz/__init__.py | 20 ++++ web_pytz/__openerp__.py | 77 ++++++++++++++ web_pytz/static/lib/moment-timezone.min.js | 6 ++ web_pytz/static/lib/moment.min.js | 7 ++ web_pytz/static/src/img/icon.png | Bin 0 -> 7939 bytes web_pytz/static/src/js/web_pytz.js | 113 +++++++++++++++++++++ web_pytz/static/test/web_pytz.js | 63 ++++++++++++ 7 files changed, 286 insertions(+) create mode 100644 web_pytz/__init__.py create mode 100644 web_pytz/__openerp__.py create mode 100644 web_pytz/static/lib/moment-timezone.min.js create mode 100644 web_pytz/static/lib/moment.min.js create mode 100644 web_pytz/static/src/img/icon.png create mode 100644 web_pytz/static/src/js/web_pytz.js create mode 100644 web_pytz/static/test/web_pytz.js diff --git a/web_pytz/__init__.py b/web_pytz/__init__.py new file mode 100644 index 00000000..9dd152f9 --- /dev/null +++ b/web_pytz/__init__.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2014 Therp BV (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## diff --git a/web_pytz/__openerp__.py b/web_pytz/__openerp__.py new file mode 100644 index 00000000..6b062f9a --- /dev/null +++ b/web_pytz/__openerp__.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# This module copyright (C) 2014 Therp BV (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## +{ + "name": "pytz support for filter domains", + "version": "1.0", + "author": "Therp BV", + "license": "AGPL-3", + "complexity": "normal", + "description": """ +Introduction +------------ +This module allows complex timezone operations in domains mimicing python's +pytz. The heavy lifting is done by http://momentjs.com/timezone. + +It is meant to allow correct filters for 'Today', 'Yesterday' etc. + +In addition to implementing a subset of `pytz.tzinfo` and +`datetime.astimezone`, there's a shortcut called `utc_today()` which returns +the beginning of the day in the current user's time zone translated to UTC, +this is equivalent to:: + + pytz.timezone(tz).localize(datetime.datetime.now().replace(hour=0, minute=0, + second=0)).astimezone(pytz.utc) + +in python. + +Usage +----- + +Depend on this module and use filters like:: + + [('write_date', '>=', utc_today().strftime('%Y-%m-%d'))] + +which displays records changed in the user's conception of today.""", + "category": "Dependency", + "depends": [ + 'web', + ], + "data": [ + ], + "js": [ + 'static/src/js/web_pytz.js', + 'static/lib/moment.min.js', + 'static/lib/moment-timezone.min.js', + ], + "css": [ + ], + "qweb": [ + ], + "test": [ + 'static/test/web_pytz.js', + ], + "auto_install": False, + "installable": True, + "application": False, + "external_dependencies": { + 'python': [], + }, +} diff --git a/web_pytz/static/lib/moment-timezone.min.js b/web_pytz/static/lib/moment-timezone.min.js new file mode 100644 index 00000000..ab528a95 --- /dev/null +++ b/web_pytz/static/lib/moment-timezone.min.js @@ -0,0 +1,6 @@ +//! moment-timezone.js +//! version : 0.2.2 +//! author : Tim Wood +//! license : MIT +//! github.com/moment/moment-timezone +!function(a,b){"use strict";"function"==typeof define&&define.amd?define(["moment"],b):"object"==typeof exports?module.exports=b(require("moment")):b(a.moment)}(this,function(a){"use strict";function b(a){return a>96?a-87:a>64?a-29:a-48}function c(a){var c,d=0,e=a.split("."),f=e[0],g=e[1]||"",h=1,i=0,j=1;for(45===a.charCodeAt(0)&&(d=1,j=-1),d;dc;c++)a[c]=Math.round((a[c-1]||0)+6e4*a[c]);a[b-1]=1/0}function f(a,b){var c,d=[];for(c=0;cB||2===B&&6>C)&&t("Moment Timezone requires Moment.js >= 2.6.0. You are using Moment.js "+a.version+". See momentjs.com"),h.prototype={_set:function(a){this.name=a.name,this.abbrs=a.abbrs,this.untils=a.untils,this.offsets=a.offsets},_index:function(a){var b,c=+a,d=this.untils;for(b=0;be;e++)if(b=g[e],c=g[e+1],d=g[e?e-1:e],c>b&&u.moveAmbiguousForward?b=c:b>d&&u.moveInvalidForward&&(b=d),f0)for(c in Ib)d=Ib[c],e=b[d],"undefined"!=typeof e&&(a[d]=e);return a}function o(a){return 0>a?Math.ceil(a):Math.floor(a)}function p(a,b,c){for(var d=""+Math.abs(a),e=a>=0;d.lengthd;d++)(c&&a[d]!==b[d]||!c&&A(a[d])!==A(b[d]))&&g++;return g+f}function x(a){if(a){var b=a.toLowerCase().replace(/(.)s$/,"$1");a=jc[a]||kc[b]||b}return a}function y(a){var b,d,e={};for(d in a)c(a,d)&&(b=x(d),b&&(e[b]=a[d]));return e}function z(b){var c,d;if(0===b.indexOf("week"))c=7,d="day";else{if(0!==b.indexOf("month"))return;c=12,d="month"}tb[b]=function(e,f){var g,h,i=tb._locale[b],j=[];if("number"==typeof e&&(f=e,e=a),h=function(a){var b=tb().utc().set(d,a);return i.call(tb._locale,b,e||"")},null!=f)return h(f);for(g=0;c>g;g++)j.push(h(g));return j}}function A(a){var b=+a,c=0;return 0!==b&&isFinite(b)&&(c=b>=0?Math.floor(b):Math.ceil(b)),c}function B(a,b){return new Date(Date.UTC(a,b+1,0)).getUTCDate()}function C(a,b,c){return hb(tb([a,11,31+b-c]),b,c).week}function D(a){return E(a)?366:365}function E(a){return a%4===0&&a%100!==0||a%400===0}function F(a){var b;a._a&&-2===a._pf.overflow&&(b=a._a[Bb]<0||a._a[Bb]>11?Bb:a._a[Cb]<1||a._a[Cb]>B(a._a[Ab],a._a[Bb])?Cb:a._a[Db]<0||a._a[Db]>23?Db:a._a[Eb]<0||a._a[Eb]>59?Eb:a._a[Fb]<0||a._a[Fb]>59?Fb:a._a[Gb]<0||a._a[Gb]>999?Gb:-1,a._pf._overflowDayOfYear&&(Ab>b||b>Cb)&&(b=Cb),a._pf.overflow=b)}function G(a){return null==a._isValid&&(a._isValid=!isNaN(a._d.getTime())&&a._pf.overflow<0&&!a._pf.empty&&!a._pf.invalidMonth&&!a._pf.nullInput&&!a._pf.invalidFormat&&!a._pf.userInvalidated,a._strict&&(a._isValid=a._isValid&&0===a._pf.charsLeftOver&&0===a._pf.unusedTokens.length)),a._isValid}function H(a){return a?a.toLowerCase().replace("_","-"):a}function I(a){for(var b,c,d,e,f=0;f0;){if(d=J(e.slice(0,b).join("-")))return d;if(c&&c.length>=b&&w(e,c,!0)>=b-1)break;b--}f++}return null}function J(a){var b=null;if(!Hb[a]&&Jb)try{b=tb.locale(),require("./locale/"+a),tb.locale(b)}catch(c){}return Hb[a]}function K(a,b){return b._isUTC?tb(a).zone(b._offset||0):tb(a).local()}function L(a){return a.match(/\[[\s\S]/)?a.replace(/^\[|\]$/g,""):a.replace(/\\/g,"")}function M(a){var b,c,d=a.match(Nb);for(b=0,c=d.length;c>b;b++)d[b]=pc[d[b]]?pc[d[b]]:L(d[b]);return function(e){var f="";for(b=0;c>b;b++)f+=d[b]instanceof Function?d[b].call(e,a):d[b];return f}}function N(a,b){return a.isValid()?(b=O(b,a.localeData()),lc[b]||(lc[b]=M(b)),lc[b](a)):a.localeData().invalidDate()}function O(a,b){function c(a){return b.longDateFormat(a)||a}var d=5;for(Ob.lastIndex=0;d>=0&&Ob.test(a);)a=a.replace(Ob,c),Ob.lastIndex=0,d-=1;return a}function P(a,b){var c,d=b._strict;switch(a){case"Q":return Zb;case"DDDD":return _b;case"YYYY":case"GGGG":case"gggg":return d?ac:Rb;case"Y":case"G":case"g":return cc;case"YYYYYY":case"YYYYY":case"GGGGG":case"ggggg":return d?bc:Sb;case"S":if(d)return Zb;case"SS":if(d)return $b;case"SSS":if(d)return _b;case"DDD":return Qb;case"MMM":case"MMMM":case"dd":case"ddd":case"dddd":return Ub;case"a":case"A":return b._locale._meridiemParse;case"X":return Xb;case"Z":case"ZZ":return Vb;case"T":return Wb;case"SSSS":return Tb;case"MM":case"DD":case"YY":case"GG":case"gg":case"HH":case"hh":case"mm":case"ss":case"ww":case"WW":return d?$b:Pb;case"M":case"D":case"d":case"H":case"h":case"m":case"s":case"w":case"W":case"e":case"E":return Pb;case"Do":return Yb;default:return c=new RegExp(Y(X(a.replace("\\","")),"i"))}}function Q(a){a=a||"";var b=a.match(Vb)||[],c=b[b.length-1]||[],d=(c+"").match(hc)||["-",0,0],e=+(60*d[1])+A(d[2]);return"+"===d[0]?-e:e}function R(a,b,c){var d,e=c._a;switch(a){case"Q":null!=b&&(e[Bb]=3*(A(b)-1));break;case"M":case"MM":null!=b&&(e[Bb]=A(b)-1);break;case"MMM":case"MMMM":d=c._locale.monthsParse(b),null!=d?e[Bb]=d:c._pf.invalidMonth=b;break;case"D":case"DD":null!=b&&(e[Cb]=A(b));break;case"Do":null!=b&&(e[Cb]=A(parseInt(b,10)));break;case"DDD":case"DDDD":null!=b&&(c._dayOfYear=A(b));break;case"YY":e[Ab]=tb.parseTwoDigitYear(b);break;case"YYYY":case"YYYYY":case"YYYYYY":e[Ab]=A(b);break;case"a":case"A":c._isPm=c._locale.isPM(b);break;case"H":case"HH":case"h":case"hh":e[Db]=A(b);break;case"m":case"mm":e[Eb]=A(b);break;case"s":case"ss":e[Fb]=A(b);break;case"S":case"SS":case"SSS":case"SSSS":e[Gb]=A(1e3*("0."+b));break;case"X":c._d=new Date(1e3*parseFloat(b));break;case"Z":case"ZZ":c._useUTC=!0,c._tzm=Q(b);break;case"dd":case"ddd":case"dddd":d=c._locale.weekdaysParse(b),null!=d?(c._w=c._w||{},c._w.d=d):c._pf.invalidWeekday=b;break;case"w":case"ww":case"W":case"WW":case"d":case"e":case"E":a=a.substr(0,1);case"gggg":case"GGGG":case"GGGGG":a=a.substr(0,2),b&&(c._w=c._w||{},c._w[a]=A(b));break;case"gg":case"GG":c._w=c._w||{},c._w[a]=tb.parseTwoDigitYear(b)}}function S(a){var c,d,e,f,g,h,i;c=a._w,null!=c.GG||null!=c.W||null!=c.E?(g=1,h=4,d=b(c.GG,a._a[Ab],hb(tb(),1,4).year),e=b(c.W,1),f=b(c.E,1)):(g=a._locale._week.dow,h=a._locale._week.doy,d=b(c.gg,a._a[Ab],hb(tb(),g,h).year),e=b(c.w,1),null!=c.d?(f=c.d,g>f&&++e):f=null!=c.e?c.e+g:g),i=ib(d,e,f,h,g),a._a[Ab]=i.year,a._dayOfYear=i.dayOfYear}function T(a){var c,d,e,f,g=[];if(!a._d){for(e=V(a),a._w&&null==a._a[Cb]&&null==a._a[Bb]&&S(a),a._dayOfYear&&(f=b(a._a[Ab],e[Ab]),a._dayOfYear>D(f)&&(a._pf._overflowDayOfYear=!0),d=db(f,0,a._dayOfYear),a._a[Bb]=d.getUTCMonth(),a._a[Cb]=d.getUTCDate()),c=0;3>c&&null==a._a[c];++c)a._a[c]=g[c]=e[c];for(;7>c;c++)a._a[c]=g[c]=null==a._a[c]?2===c?1:0:a._a[c];a._d=(a._useUTC?db:cb).apply(null,g),null!=a._tzm&&a._d.setUTCMinutes(a._d.getUTCMinutes()+a._tzm)}}function U(a){var b;a._d||(b=y(a._i),a._a=[b.year,b.month,b.day,b.hour,b.minute,b.second,b.millisecond],T(a))}function V(a){var b=new Date;return a._useUTC?[b.getUTCFullYear(),b.getUTCMonth(),b.getUTCDate()]:[b.getFullYear(),b.getMonth(),b.getDate()]}function W(a){if(a._f===tb.ISO_8601)return void $(a);a._a=[],a._pf.empty=!0;var b,c,d,e,f,g=""+a._i,h=g.length,i=0;for(d=O(a._f,a._locale).match(Nb)||[],b=0;b0&&a._pf.unusedInput.push(f),g=g.slice(g.indexOf(c)+c.length),i+=c.length),pc[e]?(c?a._pf.empty=!1:a._pf.unusedTokens.push(e),R(e,c,a)):a._strict&&!c&&a._pf.unusedTokens.push(e);a._pf.charsLeftOver=h-i,g.length>0&&a._pf.unusedInput.push(g),a._isPm&&a._a[Db]<12&&(a._a[Db]+=12),a._isPm===!1&&12===a._a[Db]&&(a._a[Db]=0),T(a),F(a)}function X(a){return a.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,function(a,b,c,d,e){return b||c||d||e})}function Y(a){return a.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}function Z(a){var b,c,e,f,g;if(0===a._f.length)return a._pf.invalidFormat=!0,void(a._d=new Date(0/0));for(f=0;fg)&&(e=g,c=b));m(a,c||b)}function $(a){var b,c,d=a._i,e=dc.exec(d);if(e){for(a._pf.iso=!0,b=0,c=fc.length;c>b;b++)if(fc[b][1].exec(d)){a._f=fc[b][0]+(e[6]||" ");break}for(b=0,c=gc.length;c>b;b++)if(gc[b][1].exec(d)){a._f+=gc[b][0];break}d.match(Vb)&&(a._f+="Z"),W(a)}else a._isValid=!1}function _(a){$(a),a._isValid===!1&&(delete a._isValid,tb.createFromInputFallback(a))}function ab(a,b){var c,d=[];for(c=0;ca&&h.setFullYear(a),h}function db(a){var b=new Date(Date.UTC.apply(null,arguments));return 1970>a&&b.setUTCFullYear(a),b}function eb(a,b){if("string"==typeof a)if(isNaN(a)){if(a=b.weekdaysParse(a),"number"!=typeof a)return null}else a=parseInt(a,10);return a}function fb(a,b,c,d,e){return e.relativeTime(b||1,!!c,a,d)}function gb(a,b,c){var d=tb.duration(a).abs(),e=yb(d.as("s")),f=yb(d.as("m")),g=yb(d.as("h")),h=yb(d.as("d")),i=yb(d.as("M")),j=yb(d.as("y")),k=e0,k[4]=c,fb.apply({},k)}function hb(a,b,c){var d,e=c-b,f=c-a.day();return f>e&&(f-=7),e-7>f&&(f+=7),d=tb(a).add(f,"d"),{week:Math.ceil(d.dayOfYear()/7),year:d.year()}}function ib(a,b,c,d,e){var f,g,h=db(a,0,1).getUTCDay();return h=0===h?7:h,c=null!=c?c:e,f=e-h+(h>d?7:0)-(e>h?7:0),g=7*(b-1)+(c-e)+f+1,{year:g>0?a:a-1,dayOfYear:g>0?g:D(a-1)+g}}function jb(b){var c=b._i,d=b._f;return b._locale=b._locale||tb.localeData(b._l),null===c||d===a&&""===c?tb.invalid({nullInput:!0}):("string"==typeof c&&(b._i=c=b._locale.preparse(c)),tb.isMoment(c)?new k(c,!0):(d?u(d)?Z(b):W(b):bb(b),new k(b)))}function kb(a,b){var c,d;if(1===b.length&&u(b[0])&&(b=b[0]),!b.length)return tb();for(c=b[0],d=1;d=0?"+":"-";return b+p(Math.abs(a),6)},gg:function(){return p(this.weekYear()%100,2)},gggg:function(){return p(this.weekYear(),4)},ggggg:function(){return p(this.weekYear(),5)},GG:function(){return p(this.isoWeekYear()%100,2)},GGGG:function(){return p(this.isoWeekYear(),4)},GGGGG:function(){return p(this.isoWeekYear(),5)},e:function(){return this.weekday()},E:function(){return this.isoWeekday()},a:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!0)},A:function(){return this.localeData().meridiem(this.hours(),this.minutes(),!1)},H:function(){return this.hours()},h:function(){return this.hours()%12||12},m:function(){return this.minutes()},s:function(){return this.seconds()},S:function(){return A(this.milliseconds()/100)},SS:function(){return p(A(this.milliseconds()/10),2)},SSS:function(){return p(this.milliseconds(),3)},SSSS:function(){return p(this.milliseconds(),3)},Z:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+p(A(a/60),2)+":"+p(A(a)%60,2)},ZZ:function(){var a=-this.zone(),b="+";return 0>a&&(a=-a,b="-"),b+p(A(a/60),2)+p(A(a)%60,2)},z:function(){return this.zoneAbbr()},zz:function(){return this.zoneName()},X:function(){return this.unix()},Q:function(){return this.quarter()}},qc={},rc=["months","monthsShort","weekdays","weekdaysShort","weekdaysMin"];nc.length;)vb=nc.pop(),pc[vb+"o"]=i(pc[vb],vb);for(;oc.length;)vb=oc.pop(),pc[vb+vb]=h(pc[vb],2);pc.DDDD=h(pc.DDD,3),m(j.prototype,{set:function(a){var b,c;for(c in a)b=a[c],"function"==typeof b?this[c]=b:this["_"+c]=b},_months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),months:function(a){return this._months[a.month()]},_monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),monthsShort:function(a){return this._monthsShort[a.month()]},monthsParse:function(a){var b,c,d;for(this._monthsParse||(this._monthsParse=[]),b=0;12>b;b++)if(this._monthsParse[b]||(c=tb.utc([2e3,b]),d="^"+this.months(c,"")+"|^"+this.monthsShort(c,""),this._monthsParse[b]=new RegExp(d.replace(".",""),"i")),this._monthsParse[b].test(a))return b},_weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdays:function(a){return this._weekdays[a.day()]},_weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysShort:function(a){return this._weekdaysShort[a.day()]},_weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),weekdaysMin:function(a){return this._weekdaysMin[a.day()]},weekdaysParse:function(a){var b,c,d;for(this._weekdaysParse||(this._weekdaysParse=[]),b=0;7>b;b++)if(this._weekdaysParse[b]||(c=tb([2e3,1]).day(b),d="^"+this.weekdays(c,"")+"|^"+this.weekdaysShort(c,"")+"|^"+this.weekdaysMin(c,""),this._weekdaysParse[b]=new RegExp(d.replace(".",""),"i")),this._weekdaysParse[b].test(a))return b},_longDateFormat:{LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY LT",LLLL:"dddd, MMMM D, YYYY LT"},longDateFormat:function(a){var b=this._longDateFormat[a];return!b&&this._longDateFormat[a.toUpperCase()]&&(b=this._longDateFormat[a.toUpperCase()].replace(/MMMM|MM|DD|dddd/g,function(a){return a.slice(1)}),this._longDateFormat[a]=b),b},isPM:function(a){return"p"===(a+"").toLowerCase().charAt(0)},_meridiemParse:/[ap]\.?m?\.?/i,meridiem:function(a,b,c){return a>11?c?"pm":"PM":c?"am":"AM"},_calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},calendar:function(a,b){var c=this._calendar[a];return"function"==typeof c?c.apply(b):c},_relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},relativeTime:function(a,b,c,d){var e=this._relativeTime[c];return"function"==typeof e?e(a,b,c,d):e.replace(/%d/i,a)},pastFuture:function(a,b){var c=this._relativeTime[a>0?"future":"past"];return"function"==typeof c?c(b):c.replace(/%s/i,b)},ordinal:function(a){return this._ordinal.replace("%d",a)},_ordinal:"%d",preparse:function(a){return a},postformat:function(a){return a},week:function(a){return hb(a,this._week.dow,this._week.doy).week},_week:{dow:0,doy:6},_invalidDate:"Invalid date",invalidDate:function(){return this._invalidDate}}),tb=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._i=b,g._f=c,g._l=e,g._strict=f,g._isUTC=!1,g._pf=d(),jb(g)},tb.suppressDeprecationWarnings=!1,tb.createFromInputFallback=f("moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.",function(a){a._d=new Date(a._i)}),tb.min=function(){var a=[].slice.call(arguments,0);return kb("isBefore",a)},tb.max=function(){var a=[].slice.call(arguments,0);return kb("isAfter",a)},tb.utc=function(b,c,e,f){var g;return"boolean"==typeof e&&(f=e,e=a),g={},g._isAMomentObject=!0,g._useUTC=!0,g._isUTC=!0,g._l=e,g._i=b,g._f=c,g._strict=f,g._pf=d(),jb(g).utc()},tb.unix=function(a){return tb(1e3*a)},tb.duration=function(a,b){var d,e,f,g,h=a,i=null;return tb.isDuration(a)?h={ms:a._milliseconds,d:a._days,M:a._months}:"number"==typeof a?(h={},b?h[b]=a:h.milliseconds=a):(i=Lb.exec(a))?(d="-"===i[1]?-1:1,h={y:0,d:A(i[Cb])*d,h:A(i[Db])*d,m:A(i[Eb])*d,s:A(i[Fb])*d,ms:A(i[Gb])*d}):(i=Mb.exec(a))?(d="-"===i[1]?-1:1,f=function(a){var b=a&&parseFloat(a.replace(",","."));return(isNaN(b)?0:b)*d},h={y:f(i[2]),M:f(i[3]),d:f(i[4]),h:f(i[5]),m:f(i[6]),s:f(i[7]),w:f(i[8])}):"object"==typeof h&&("from"in h||"to"in h)&&(g=r(tb(h.from),tb(h.to)),h={},h.ms=g.milliseconds,h.M=g.months),e=new l(h),tb.isDuration(a)&&c(a,"_locale")&&(e._locale=a._locale),e},tb.version=wb,tb.defaultFormat=ec,tb.ISO_8601=function(){},tb.momentProperties=Ib,tb.updateOffset=function(){},tb.relativeTimeThreshold=function(b,c){return mc[b]===a?!1:c===a?mc[b]:(mc[b]=c,!0)},tb.lang=f("moment.lang is deprecated. Use moment.locale instead.",function(a,b){return tb.locale(a,b)}),tb.locale=function(a,b){var c;return a&&(c="undefined"!=typeof b?tb.defineLocale(a,b):tb.localeData(a),c&&(tb.duration._locale=tb._locale=c)),tb._locale._abbr},tb.defineLocale=function(a,b){return null!==b?(b.abbr=a,Hb[a]||(Hb[a]=new j),Hb[a].set(b),tb.locale(a),Hb[a]):(delete Hb[a],null)},tb.langData=f("moment.langData is deprecated. Use moment.localeData instead.",function(a){return tb.localeData(a)}),tb.localeData=function(a){var b;if(a&&a._locale&&a._locale._abbr&&(a=a._locale._abbr),!a)return tb._locale;if(!u(a)){if(b=J(a))return b;a=[a]}return I(a)},tb.isMoment=function(a){return a instanceof k||null!=a&&c(a,"_isAMomentObject")},tb.isDuration=function(a){return a instanceof l};for(vb=rc.length-1;vb>=0;--vb)z(rc[vb]);tb.normalizeUnits=function(a){return x(a)},tb.invalid=function(a){var b=tb.utc(0/0);return null!=a?m(b._pf,a):b._pf.userInvalidated=!0,b},tb.parseZone=function(){return tb.apply(null,arguments).parseZone()},tb.parseTwoDigitYear=function(a){return A(a)+(A(a)>68?1900:2e3)},m(tb.fn=k.prototype,{clone:function(){return tb(this)},valueOf:function(){return+this._d+6e4*(this._offset||0)},unix:function(){return Math.floor(+this/1e3)},toString:function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},toDate:function(){return this._offset?new Date(+this):this._d},toISOString:function(){var a=tb(this).utc();return 00:!1},parsingFlags:function(){return m({},this._pf)},invalidAt:function(){return this._pf.overflow},utc:function(a){return this.zone(0,a)},local:function(a){return this._isUTC&&(this.zone(0,a),this._isUTC=!1,a&&this.add(this._dateTzOffset(),"m")),this},format:function(a){var b=N(this,a||tb.defaultFormat);return this.localeData().postformat(b)},add:s(1,"add"),subtract:s(-1,"subtract"),diff:function(a,b,c){var d,e,f,g=K(a,this),h=6e4*(this.zone()-g.zone());return b=x(b),"year"===b||"month"===b?(d=432e5*(this.daysInMonth()+g.daysInMonth()),e=12*(this.year()-g.year())+(this.month()-g.month()),f=this-tb(this).startOf("month")-(g-tb(g).startOf("month")),f-=6e4*(this.zone()-tb(this).startOf("month").zone()-(g.zone()-tb(g).startOf("month").zone())),e+=f/d,"year"===b&&(e/=12)):(d=this-g,e="second"===b?d/1e3:"minute"===b?d/6e4:"hour"===b?d/36e5:"day"===b?(d-h)/864e5:"week"===b?(d-h)/6048e5:d),c?e:o(e)},from:function(a,b){return tb.duration({to:this,from:a}).locale(this.locale()).humanize(!b)},fromNow:function(a){return this.from(tb(),a)},calendar:function(a){var b=a||tb(),c=K(b,this).startOf("day"),d=this.diff(c,"days",!0),e=-6>d?"sameElse":-1>d?"lastWeek":0>d?"lastDay":1>d?"sameDay":2>d?"nextDay":7>d?"nextWeek":"sameElse";return this.format(this.localeData().calendar(e,this))},isLeapYear:function(){return E(this.year())},isDST:function(){return this.zone()+a):+this.clone().startOf(b)>+tb(a).startOf(b)},isBefore:function(a,b){return b=x("undefined"!=typeof b?b:"millisecond"),"millisecond"===b?(a=tb.isMoment(a)?a:tb(a),+a>+this):+this.clone().startOf(b)<+tb(a).startOf(b)},isSame:function(a,b){return b=x(b||"millisecond"),"millisecond"===b?(a=tb.isMoment(a)?a:tb(a),+this===+a):+this.clone().startOf(b)===+K(a,this).startOf(b)},min:f("moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548",function(a){return a=tb.apply(null,arguments),this>a?this:a}),max:f("moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548",function(a){return a=tb.apply(null,arguments),a>this?this:a}),zone:function(a,b){var c,d=this._offset||0;return null==a?this._isUTC?d:this._dateTzOffset():("string"==typeof a&&(a=Q(a)),Math.abs(a)<16&&(a=60*a),!this._isUTC&&b&&(c=this._dateTzOffset()),this._offset=a,this._isUTC=!0,null!=c&&this.subtract(c,"m"),d!==a&&(!b||this._changeInProgress?t(this,tb.duration(d-a,"m"),1,!1):this._changeInProgress||(this._changeInProgress=!0,tb.updateOffset(this,!0),this._changeInProgress=null)),this)},zoneAbbr:function(){return this._isUTC?"UTC":""},zoneName:function(){return this._isUTC?"Coordinated Universal Time":""},parseZone:function(){return this._tzm?this.zone(this._tzm):"string"==typeof this._i&&this.zone(this._i),this},hasAlignedHourOffset:function(a){return a=a?tb(a).zone():0,(this.zone()-a)%60===0},daysInMonth:function(){return B(this.year(),this.month())},dayOfYear:function(a){var b=yb((tb(this).startOf("day")-tb(this).startOf("year"))/864e5)+1;return null==a?b:this.add(a-b,"d")},quarter:function(a){return null==a?Math.ceil((this.month()+1)/3):this.month(3*(a-1)+this.month()%3)},weekYear:function(a){var b=hb(this,this.localeData()._week.dow,this.localeData()._week.doy).year;return null==a?b:this.add(a-b,"y")},isoWeekYear:function(a){var b=hb(this,1,4).year;return null==a?b:this.add(a-b,"y")},week:function(a){var b=this.localeData().week(this);return null==a?b:this.add(7*(a-b),"d")},isoWeek:function(a){var b=hb(this,1,4).week;return null==a?b:this.add(7*(a-b),"d")},weekday:function(a){var b=(this.day()+7-this.localeData()._week.dow)%7;return null==a?b:this.add(a-b,"d")},isoWeekday:function(a){return null==a?this.day()||7:this.day(this.day()%7?a:a-7)},isoWeeksInYear:function(){return C(this.year(),1,4)},weeksInYear:function(){var a=this.localeData()._week;return C(this.year(),a.dow,a.doy)},get:function(a){return a=x(a),this[a]()},set:function(a,b){return a=x(a),"function"==typeof this[a]&&this[a](b),this},locale:function(b){var c;return b===a?this._locale._abbr:(c=tb.localeData(b),null!=c&&(this._locale=c),this)},lang:f("moment().lang() is deprecated. Use moment().localeData() instead.",function(b){return b===a?this.localeData():this.locale(b)}),localeData:function(){return this._locale},_dateTzOffset:function(){return 15*Math.round(this._d.getTimezoneOffset()/15)}}),tb.fn.millisecond=tb.fn.milliseconds=ob("Milliseconds",!1),tb.fn.second=tb.fn.seconds=ob("Seconds",!1),tb.fn.minute=tb.fn.minutes=ob("Minutes",!1),tb.fn.hour=tb.fn.hours=ob("Hours",!0),tb.fn.date=ob("Date",!0),tb.fn.dates=f("dates accessor is deprecated. Use date instead.",ob("Date",!0)),tb.fn.year=ob("FullYear",!0),tb.fn.years=f("years accessor is deprecated. Use year instead.",ob("FullYear",!0)),tb.fn.days=tb.fn.day,tb.fn.months=tb.fn.month,tb.fn.weeks=tb.fn.week,tb.fn.isoWeeks=tb.fn.isoWeek,tb.fn.quarters=tb.fn.quarter,tb.fn.toJSON=tb.fn.toISOString,m(tb.duration.fn=l.prototype,{_bubble:function(){var a,b,c,d=this._milliseconds,e=this._days,f=this._months,g=this._data,h=0;g.milliseconds=d%1e3,a=o(d/1e3),g.seconds=a%60,b=o(a/60),g.minutes=b%60,c=o(b/60),g.hours=c%24,e+=o(c/24),h=o(pb(e)),e-=o(qb(h)),f+=o(e/30),e%=30,h+=o(f/12),f%=12,g.days=e,g.months=f,g.years=h},abs:function(){return this._milliseconds=Math.abs(this._milliseconds),this._days=Math.abs(this._days),this._months=Math.abs(this._months),this._data.milliseconds=Math.abs(this._data.milliseconds),this._data.seconds=Math.abs(this._data.seconds),this._data.minutes=Math.abs(this._data.minutes),this._data.hours=Math.abs(this._data.hours),this._data.months=Math.abs(this._data.months),this._data.years=Math.abs(this._data.years),this},weeks:function(){return o(this.days()/7)},valueOf:function(){return this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*A(this._months/12)},humanize:function(a){var b=gb(this,!a,this.localeData());return a&&(b=this.localeData().pastFuture(+this,b)),this.localeData().postformat(b)},add:function(a,b){var c=tb.duration(a,b);return this._milliseconds+=c._milliseconds,this._days+=c._days,this._months+=c._months,this._bubble(),this},subtract:function(a,b){var c=tb.duration(a,b);return this._milliseconds-=c._milliseconds,this._days-=c._days,this._months-=c._months,this._bubble(),this},get:function(a){return a=x(a),this[a.toLowerCase()+"s"]()},as:function(a){var b,c;if(a=x(a),"month"===a||"year"===a)return b=this._days+this._milliseconds/864e5,c=this._months+12*pb(b),"month"===a?c:c/12;switch(b=this._days+qb(this._months/12),a){case"week":return b/7+this._milliseconds/6048e5;case"day":return b+this._milliseconds/864e5;case"hour":return 24*b+this._milliseconds/36e5;case"minute":return 24*b*60+this._milliseconds/6e4;case"second":return 24*b*60*60+this._milliseconds/1e3;case"millisecond":return Math.floor(24*b*60*60*1e3)+this._milliseconds;default:throw new Error("Unknown unit "+a)}},lang:tb.fn.lang,locale:tb.fn.locale,toIsoString:f("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",function(){return this.toISOString()}),toISOString:function(){var a=Math.abs(this.years()),b=Math.abs(this.months()),c=Math.abs(this.days()),d=Math.abs(this.hours()),e=Math.abs(this.minutes()),f=Math.abs(this.seconds()+this.milliseconds()/1e3);return this.asSeconds()?(this.asSeconds()<0?"-":"")+"P"+(a?a+"Y":"")+(b?b+"M":"")+(c?c+"D":"")+(d||e||f?"T":"")+(d?d+"H":"")+(e?e+"M":"")+(f?f+"S":""):"P0D"},localeData:function(){return this._locale}}),tb.duration.fn.toString=tb.duration.fn.toISOString;for(vb in ic)c(ic,vb)&&rb(vb.toLowerCase());tb.duration.fn.asMilliseconds=function(){return this.as("ms")},tb.duration.fn.asSeconds=function(){return this.as("s")},tb.duration.fn.asMinutes=function(){return this.as("m")},tb.duration.fn.asHours=function(){return this.as("h")},tb.duration.fn.asDays=function(){return this.as("d")},tb.duration.fn.asWeeks=function(){return this.as("weeks")},tb.duration.fn.asMonths=function(){return this.as("M")},tb.duration.fn.asYears=function(){return this.as("y")},tb.locale("en",{ordinal:function(a){var b=a%10,c=1===A(a%100/10)?"th":1===b?"st":2===b?"nd":3===b?"rd":"th"; +return a+c}}),Jb?module.exports=tb:"function"==typeof define&&define.amd?(define("moment",function(a,b,c){return c.config&&c.config()&&c.config().noGlobal===!0&&(xb.moment=ub),tb}),sb(!0)):sb()}).call(this); \ No newline at end of file diff --git a/web_pytz/static/src/img/icon.png b/web_pytz/static/src/img/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f1006195e0220e5b38e4a1b8f17870ec9359f7bb GIT binary patch literal 7939 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 literal 0 HcmV?d00001 diff --git a/web_pytz/static/src/js/web_pytz.js b/web_pytz/static/src/js/web_pytz.js new file mode 100644 index 00000000..bd39c36e --- /dev/null +++ b/web_pytz/static/src/js/web_pytz.js @@ -0,0 +1,113 @@ +//-*- coding: utf-8 -*- +//############################################################################ +// +// OpenERP, Open Source Management Solution +// This module copyright (C) 2014 Therp BV (). +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +//############################################################################ + +openerp.web_pytz = function(instance) +{ + var original_pyeval_context = instance.web.pyeval.context; + + var tzinfo = py.type('tzinfo', null, { + tzname: function() + { + var args = py.PY_parseArgs(arguments, 'dst'); + return py.str.fromJSON(this.zone.name); + }, + localize: function() + { + var args = py.PY_parseArgs(arguments, 'dst'), + result = py.PY_call( + args.dst.__class__, + [ + py.float.fromJSON(args.dst.year), + py.float.fromJSON(args.dst.month), + py.float.fromJSON(args.dst.day), + py.float.fromJSON(args.dst.hour), + py.float.fromJSON(args.dst.minute), + py.float.fromJSON(args.dst.second), + py.float.fromJSON(args.dst.microsecond), + ]); + result.tzinfo = this; + return result; + }, + }); + + var pytz = py.PY_call(py.object); + pytz.timezone = py.PY_def.fromJSON(function() + { + var args = py.PY_parseArgs(arguments, 'tz_name'), + tz = moment.tz.zone(args.tz_name.toJSON()), + result = py.PY_call(tzinfo); + result.zone = tz; + return result; + }); + pytz.utc = py.PY_call( + py.PY_getAttr(pytz, 'timezone'), [py.str.fromJSON('UTC')]); + + function astimezone() + { + var args = py.PY_parseArgs(arguments, 'tzinfo'); + // TODO: check that we only do this with localized dts + var d = moment.tz( + { + year: this.year, + month: this.month - 1, + day: this.day, + hour: this.hour, + minute: this.minute, + second: this.second, + }, + this.tzinfo.zone.name) + .tz(args.tzinfo.zone.name); + return py.PY_call( + this.__class__, + [d.year(), d.month() + 1, d.date(), d.hour(), d.minute(), + d.second()]); + }; + + instance.web.pyeval.context = function () + { + var ctx = original_pyeval_context(); + ctx.datetime.datetime.astimezone = astimezone; + return _.extend( + ctx, + { + pytz: pytz, + utc_today: function(args, kwargs) + { + var timezone = py.PY_call( + py.PY_getAttr(pytz, 'timezone'), + [py.str.fromJSON( + ctx.tz || (args.length ? args[0] : 'UTC'))]), + now = py.PY_call( + py.PY_getAttr(ctx.datetime.datetime, 'now')), + localized = py.PY_call( + py.PY_getAttr(timezone, 'localize'), + [now]); + localized.hour = 0; + localized.minute = 0; + localized.second = 0; + localized.millisecond = 0; + return py.PY_call( + py.PY_getAttr(localized, 'astimezone'), + [py.PY_getAttr(pytz, 'utc')]); + } + }); + } +} diff --git a/web_pytz/static/test/web_pytz.js b/web_pytz/static/test/web_pytz.js new file mode 100644 index 00000000..197e634b --- /dev/null +++ b/web_pytz/static/test/web_pytz.js @@ -0,0 +1,63 @@ +//-*- coding: utf-8 -*- +//############################################################################ +// +// OpenERP, Open Source Management Solution +// This module copyright (C) 2014 Therp BV (). +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +//############################################################################ + +openerp.testing.section( + 'timezones', + {dependencies: ['web.coresetup', 'web.pyeval']}, + function(test) + { + test('basic', function(instance) + { + openerp.web_pytz(instance); + var eval = function(expression, context) + { + var result_domain = instance.web.pyeval.eval( + 'domain', "[['a', '=', " + expression + "]]", + context || {}, {}); + return result_domain[0][2]; + } + + var result; + + result = eval( + "pytz.timezone('Europe/Amsterdam').localize(datetime.datetime(2014, 10, 6, 0, 0, 0)).astimezone(pytz.timezone('utc')).strftime('%Y-%m-%d %H:%M:%S')"); + ok(result == '2014-10-05 22:00:00', 'day start in Amsterdam, summer'); + + result = eval( + "pytz.timezone('Europe/Amsterdam').localize(datetime.datetime(2014, 12, 6, 0, 0, 0)).astimezone(pytz.timezone('utc')).strftime('%Y-%m-%d %H:%M:%S')"); + ok(result == '2014-12-05 23:00:00', 'day start in Amsterdam, winter'); + + result = eval( + "pytz.timezone('America/Toronto').localize(datetime.datetime(2014, 10, 6, 0, 0, 0)).astimezone(pytz.utc).strftime('%Y-%m-%d %H:%M:%S')"); + ok(result == '2014-10-06 04:00:00', 'day start in Torronto'); + + result = eval( + "pytz.timezone('Asia/Shanghai').localize(datetime.datetime(2014, 10, 6, 0, 0, 0)).astimezone(pytz.utc).strftime('%Y-%m-%d %H:%M:%S')"); + ok(result == '2014-10-05 16:00:00', 'day start in Shanghai'); + + _.each(['Europe/Amsterdam', 'America/Toronto', 'Asia/Shanghai'], function(tz) + { + result = eval("utc_today().strftime('%Y-%m-%d %H:%M:%S')", {tz: tz}); + var now = moment(); + ok(result == moment.tz([now.year(), now.month(), now.date()], tz).hour(0).utc().format('YYYY-MM-DD HH:mm:ss'), _.str.sprintf('day start with shortcut in %s', tz)); + }); + }); + });