diff --git a/Changelog b/Changelog
index 559cc525..0da1b0d6 100644
--- a/Changelog
+++ b/Changelog
@@ -10,9 +10,10 @@ version 1.5.1 (not yet released)
* '360_day' was missing from list of 'idealized' calendars.
* fixed a bug that led to subclasses losing their type identity upon
pickling (issue #251, PR #252).
- * Change default behavior of proleptic_gregorian to has_year_zero=T to
- conform to upcoming changes in CF v1.9 (PR #238). Issue warning when trying
- to create a cftime.datetime instance that is not allowed in CF.
+ * Change default behavior of proleptic_gregorian to has_year_zero=T
+ (to be consistent with ISO-8601 since CF does not specify the year zero convention
+ for this calendar). Issue warning when trying to
+ to create a cftime.datetime instance that is not allowed in CF (PR #238).
version 1.5.0 (release tag v1.5.0.rel)
diff --git a/README.md b/README.md
index c4664097..1380aca1 100644
--- a/README.md
+++ b/README.md
@@ -12,6 +12,14 @@ Time-handling functionality from netcdf4-python
## News
For details on the latest updates, see the [Changelog](https://github.com/Unidata/cftime/blob/master/Changelog).
+10/1/2021: Version 1.5.1 released. Changed default behavior of ``proleptic_gregorian``
+to has_year_zero=T (since it is allowed in ISO-8601 and CF does not specify the
+year zero convention for this calendar). Raise warning message when trying
+to create a calendar that is not supported by CF version 1.9 (no years < 1
+allowed for 'standard'/'gregorian' or 'julian' calendars).
+Added support for "common_year" and "common_years" units for "noleap"
+and "365_day" calendars.
+
5/20/2021: Version 1.5.0 released. Includes support for astronomical year numbering
(including the year zero) for real-world calendars ('julian', 'gregorian'/'standard',
and 'proleptic_gregorian') using 'has_year_zero' `cftime.datetime` kwarg.
diff --git a/docs/_build/doctrees/api.doctree b/docs/_build/doctrees/api.doctree
index 67e79299..efedee63 100644
Binary files a/docs/_build/doctrees/api.doctree and b/docs/_build/doctrees/api.doctree differ
diff --git a/docs/_build/doctrees/environment.pickle b/docs/_build/doctrees/environment.pickle
index 01209583..7a700b49 100644
Binary files a/docs/_build/doctrees/environment.pickle and b/docs/_build/doctrees/environment.pickle differ
diff --git a/docs/_build/doctrees/installing.doctree b/docs/_build/doctrees/installing.doctree
index ca2c5c47..1bd988fe 100644
Binary files a/docs/_build/doctrees/installing.doctree and b/docs/_build/doctrees/installing.doctree differ
diff --git a/docs/_build/html/api.html b/docs/_build/html/api.html
index ab6c43ea..9dfeee1e 100644
--- a/docs/_build/html/api.html
+++ b/docs/_build/html/api.html
@@ -4,7 +4,8 @@
-
+
Installation
-
+
Required dependencies
Python: >3.2
numpy (1.7 or later)
-
-
+
+
Instructions
The easiest way to get everything installed is to use conda command line tool:
$ conda install cftime
@@ -58,16 +59,16 @@ Instructions
-
-
+
+
Developing
When developing we recommend cloning the GitHub repository,
building the extension in-place with cython 0.19 or later
python setup.py build_ext --inplace
and running the test suite to check if the changes are passing the tests
pytest --pyargs test
-
-
+
+
diff --git a/docs/_build/html/searchindex.js b/docs/_build/html/searchindex.js
index 9a0e108c..400b8307 100644
--- a/docs/_build/html/searchindex.js
+++ b/docs/_build/html/searchindex.js
@@ -1 +1 @@
-Search.setIndex({docnames:["api","index","installing"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,sphinx:56},filenames:["api.rst","index.rst","installing.rst"],objects:{"":{cftime:[0,0,0,"-"]},"cftime.datetime":{change_calendar:[0,3,1,""],fromordinal:[0,3,1,""],isoformat:[0,3,1,""],replace:[0,3,1,""],strftime:[0,3,1,""],timetuple:[0,3,1,""],toordinal:[0,3,1,""]},cftime:{date2index:[0,1,1,""],date2num:[0,1,1,""],datetime:[0,2,1,""],num2date:[0,1,1,""],num2pydate:[0,1,1,""],time2index:[0,1,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:method"},terms:{"100":[],"1582":0,"1st":0,"360_dai":0,"365_dai":0,"366_dai":0,"4712":0,"4713":0,"4714":0,"8601":0,"boolean":[],"class":0,"default":[0,2],"int":0,"new":[0,2],"return":0,"static":0,"true":0,For:0,Has:0,The:[0,2],Then:2,__add__:0,__format__:0,__repr__:0,__str__:0,__sub__:0,_cftime:[],accuraci:0,after:0,all:0,all_leap:0,allow:0,allowd:0,also:2,alwai:0,api:1,appear:2,appli:0,approxim:0,arg:[],argument:0,arrai:0,associ:0,assum:0,astronom:0,attribut:0,auto:0,awar:0,base:0,befor:[0,2],behavior:0,being:2,between:0,blank:0,breakpoint:0,build:2,build_ext:2,calcul:0,calendar:0,can:0,cannot:0,cartopi:2,cfconvent:[],cftime:[0,2],chang:2,change_calendar:0,channel:2,check:2,climat:1,clone:2,closest:0,command:2,commun:2,compar:[],comparison:0,complet:0,comput:[],conda:2,conform:[0,1],contain:0,control:0,convent:[0,1],correspond:0,creat:0,ctime:0,current:0,cython:2,dai:0,date2index:0,date2num:0,date:0,datefromjuliandai:[],datetim:0,datetimeallleap:[],datetimegregorian:[],datetimejulian:[],datetimenoleap:[],datetimeprolepticgregorian:[],dayofwk:0,dayofyr:0,daysinmonth:0,decod:1,defin:0,depend:1,describ:0,determin:[],develop:1,differ:[],difficult:2,direct:0,document:0,don:2,dst:0,easiest:2,either:0,entri:0,equival:0,error:0,even:0,everyth:2,exact:0,exist:0,explicit:0,extens:2,fall:[],fals:0,field:0,file:1,first:[0,2],flag:0,follow:[],forecast:1,forg:2,form:0,format:0,found:0,fraction:0,from:0,fromordin:0,get:2,github:2,given:0,gregorian:0,has_year_zero:0,have:[0,2],histor:0,hour:0,http:[],ideal:0,ignor:0,includ:0,increas:0,index:[0,1],indic:0,inplac:2,input:0,instal:1,instanc:0,instruct:1,integ:0,invers:0,iso:0,isoformat:0,its:0,januari:0,jdai:0,julian:0,juliandayfromd:[],just:0,keyword:0,kwarg:0,last:[],later:2,librari:1,like:[],line:2,list:0,localtim:0,mai:2,maintain:2,match:0,mean:0,metadata:0,method:0,microsecond:0,millisecond:0,mimic:0,minut:0,mix:0,modul:1,month:0,months_sinc:0,must:0,nativ:0,nctime:0,nearest:0,need:[0,2],netcdf:[0,1],no_leap:[],noleap:0,none:0,noon:0,note:0,novemb:0,num2dat:0,num2pyd:0,number:0,numer:0,numpi:2,object:0,offset:0,one:0,onli:0,only_use_cftime_datetim:0,only_use_python_datetim:0,oper:0,option:0,order:0,ordin:0,org:[],origin:0,other:0,otherwis:0,over:0,overload:0,page:1,part:0,pass:2,perfectli:0,phoni:[],pip:2,place:2,possibl:0,preced:0,produc:0,prolept:0,proleptic_gregorian:0,pyarg:2,pynio:2,pytest:2,python:[0,1,2],rais:0,real:0,recommend:2,refer:0,releas:2,replac:0,repositori:2,repres:0,requir:1,return_tupl:[],ridden:0,rist:[],run:2,same:0,search:1,second:0,section:0,see:0,select:0,self:0,sep:0,sequenc:0,set:0,setup:2,should:0,sinc:0,some:0,specif:0,specifi:0,standard:0,start:0,store:0,strftime:0,string:0,strptime:0,struct_tim:0,subclass:0,subtract:[],suit:2,support:0,sure:2,synonym:0,system:0,test:2,than:0,thei:0,thi:0,time2index:0,time:[0,1],timedelta:0,timespec:0,timetupl:0,tool:2,toordin:0,unit:[0,1],unless:0,updat:2,use:[0,2],use_only_python_datetim:0,used:0,uses:[],using:[0,2],utc:0,valid:0,valu:[0,1],variabl:[0,1],versa:[],version:0,vice:[],wai:2,weekdai:0,when:2,where:0,whether:[],which:0,within:0,work:0,world:0,ydai:0,year:0,you:2,zero:0,zone:0},titles:["API","cftime","Installation"],titleterms:{api:0,cftime:1,content:1,depend:2,develop:2,indic:1,instal:2,instruct:2,requir:2,tabl:1}})
\ No newline at end of file
+Search.setIndex({docnames:["api","index","installing"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":2,"sphinx.domains.rst":2,"sphinx.domains.std":1,"sphinx.ext.intersphinx":1,sphinx:56},filenames:["api.rst","index.rst","installing.rst"],objects:{"":{cftime:[0,0,0,"-"]},"cftime.datetime":{change_calendar:[0,3,1,""],fromordinal:[0,3,1,""],isoformat:[0,3,1,""],replace:[0,3,1,""],strftime:[0,3,1,""],timetuple:[0,3,1,""],toordinal:[0,3,1,""]},cftime:{date2index:[0,1,1,""],date2num:[0,1,1,""],datetime:[0,2,1,""],num2date:[0,1,1,""],num2pydate:[0,1,1,""],time2index:[0,1,1,""]}},objnames:{"0":["py","module","Python module"],"1":["py","function","Python function"],"2":["py","class","Python class"],"3":["py","method","Python method"]},objtypes:{"0":"py:module","1":"py:function","2":"py:class","3":"py:method"},terms:{"100":[],"1582":0,"1st":0,"360_dai":0,"365_dai":0,"366_dai":0,"4712":0,"4713":0,"4714":0,"8601":0,"boolean":[],"class":0,"default":[0,2],"int":0,"new":[0,2],"return":0,"static":0,"true":0,For:0,Has:0,The:[0,2],Then:2,__add__:0,__format__:0,__repr__:0,__str__:0,__sub__:0,_cftime:[],accuraci:0,adopt:0,after:0,all:0,all_leap:0,allow:0,allowd:[],also:2,alwai:0,api:1,appear:2,appli:0,approxim:0,arg:[],argument:0,arrai:0,associ:0,assum:0,astronom:0,attribut:0,auto:0,awar:0,base:0,befor:[0,2],behavior:0,being:2,between:0,blank:0,breakpoint:0,build:2,build_ext:2,calcul:0,calendar:0,can:0,cannot:0,cartopi:2,cfconvent:[],cftime:[0,2],chang:2,change_calendar:0,channel:2,check:2,climat:1,clone:2,closest:0,command:2,common_year:0,commun:2,compar:[],comparison:0,complet:0,comput:[],conda:2,conform:[0,1],contain:0,control:0,convent:[0,1],correspond:0,creat:0,ctime:0,current:0,cython:2,dai:0,date2index:0,date2num:0,date:0,datefromjuliandai:[],datetim:0,datetimeallleap:[],datetimegregorian:[],datetimejulian:[],datetimenoleap:[],datetimeprolepticgregorian:[],dayofwk:0,dayofyr:0,daysinmonth:0,decod:1,defin:0,depend:1,describ:0,determin:[],develop:1,differ:[],difficult:2,direct:0,document:0,doe:0,don:2,dst:0,easiest:2,either:0,entri:0,equival:0,error:0,even:0,everyth:2,exact:0,exist:0,explicit:0,extens:2,fall:[],fals:0,field:0,file:1,first:[0,2],flag:0,follow:[],forecast:1,forg:2,form:0,format:0,found:0,fraction:0,from:0,fromordin:0,get:2,github:2,given:0,gregorian:0,has:0,has_year_zero:0,have:[0,2],histor:0,hour:0,http:[],ideal:0,ignor:0,includ:0,increas:0,index:[0,1],indic:0,inplac:2,input:0,instal:1,instanc:0,instruct:1,integ:0,invers:0,iso:0,isoformat:0,its:0,januari:0,jdai:0,julian:0,juliandayfromd:[],just:0,keyword:0,kwarg:0,last:[],later:2,librari:1,like:[],line:2,list:0,localtim:0,mai:2,maintain:2,match:0,mean:0,mention:0,metadata:0,method:0,microsecond:0,millisecond:0,mimic:0,minut:0,mix:0,modul:1,month:0,months_sinc:[],must:0,nativ:0,nctime:0,nearest:0,need:[0,2],netcdf:[0,1],no_leap:[],noleap:0,none:0,noon:0,note:0,novemb:0,num2dat:0,num2pyd:0,number:0,numer:0,numpi:2,object:0,offset:0,one:0,onli:0,only_use_cftime_datetim:0,only_use_python_datetim:0,oper:0,option:0,order:0,ordin:0,org:[],origin:0,other:0,otherwis:0,over:0,overload:0,page:1,part:0,pass:2,perfectli:0,phoni:[],pip:2,place:2,possibl:0,preced:0,produc:0,prolept:0,proleptic_gregorian:0,pyarg:2,pynio:2,pytest:2,python:[0,1,2],rais:0,real:0,recommend:2,refer:0,releas:2,replac:0,repositori:2,repres:0,requir:1,return_tupl:[],ridden:0,rist:[],run:2,same:0,search:1,second:0,section:0,see:0,select:0,self:0,sep:0,sequenc:0,set:0,setup:2,should:0,sinc:0,some:0,specif:0,specifi:0,standard:0,start:0,store:0,strftime:0,string:0,strptime:0,struct_tim:0,subclass:0,subtract:[],suit:2,support:0,sure:2,synonym:0,system:0,test:2,than:0,thei:0,thi:0,time2index:0,time:[0,1],timedelta:0,timespec:0,timetupl:0,tool:2,toordin:0,unit:[0,1],unless:0,updat:2,use:[0,2],use_only_python_datetim:0,used:0,uses:[],using:[0,2],utc:0,valid:0,valu:[0,1],variabl:[0,1],versa:[],version:0,vice:[],wai:2,weekdai:0,when:2,where:0,whether:0,which:0,within:0,work:0,world:0,ydai:0,year:0,you:2,zero:0,zone:0},titles:["API","cftime","Installation"],titleterms:{api:0,cftime:1,content:1,depend:2,develop:2,indic:1,instal:2,instruct:2,requir:2,tabl:1}})
\ No newline at end of file
diff --git a/src/cftime/_cftime.pyx b/src/cftime/_cftime.pyx
index cd1df3bf..88d95d3d 100644
--- a/src/cftime/_cftime.pyx
+++ b/src/cftime/_cftime.pyx
@@ -163,6 +163,9 @@ def date2num(dates,units,calendar=None,has_year_zero=None):
CF version 1.9 conventions (False for 'julian', 'gregorian'/'standard', True
for 'proleptic_gregorian' (ISO 8601) and True for the idealized
calendars 'noleap'/'365_day', '360_day', 366_day'/'all_leap')
+ Note that CF v1.9 does not specifically mention whether year zero
+ is allowed in the proleptic_gregorian calendar, but ISO-8601 has
+ a year zero so we have adopted this as the default.
The defaults can only be over-ridden for the real-world calendars,
for the the idealized calendars the year zero
always exists and the has_year_zero kwarg is ignored.
@@ -1029,9 +1032,12 @@ The default format of the string produced by strftime is controlled by self.form
has_year_zero=True
else:
has_year_zero = _year_zero_defaults(calendar)
- # warn if requested date not allowed by CF.
- if (calendar in ['julian','gregorian','standard'] and year <= 0) or\
- (calendar == 'proleptic_gregorian' and not has_year_zero and year < 1):
+ # warn if requested date not allowed by CF
+ # (no years < 1 in mixed Julian/Gregorian calendar).
+ # CF version 1.9 does not specify whether a year zero should exist
+ # for the proleptic_gregorian calendar. IS0 8601 uses proleptic_gregorian
+ # and has a year zero, so for now this is the default in cftime.
+ if calendar in ['julian','gregorian','standard'] and year <= 0:
warnings.warn(cfwarnmsg,category=CFWarning)
# raise exception if year zero requested but has_year_zero set
# to False (issue #248).
diff --git a/test/test_cftime.py b/test/test_cftime.py
index 22a689ff..c5de9406 100644
--- a/test/test_cftime.py
+++ b/test/test_cftime.py
@@ -1398,67 +1398,6 @@ def not_comparable_5():
for func in [not_comparable_1, not_comparable_2, not_comparable_3, not_comparable_4, not_comparable_5]:
self.assertRaises(TypeError, func)
- @pytest.mark.skipif(sys.version_info.major != 2,
- reason='python2 specific, non-comparable test')
- def test_richcmp_py2(self):
- class Rich(object):
- """Dummy class with traditional rich comparison support."""
- def __lt__(self, other):
- raise NotImplementedError('__lt__')
- def __le__(self, other):
- raise NotImplementedError('__le__')
- def __eq__(self, other):
- raise NotImplementedError('__eq__')
- def __ne__(self, other):
- raise NotImplementedError('__ne__')
- def __gt__(self, other):
- raise NotImplementedError('__gt__')
- def __ge__(self, other):
- raise NotImplementedError('__ge__')
-
- class CythonRich(object):
- """Dummy class with spoof cython rich comparison support."""
- def __richcmp__(self, other):
- """
- This method is never called. However it is introspected
- by the cftime.datetime.__richcmp__ method, which will then
- return NotImplemented, causing Python to call this classes
- __cmp__ method as a back-stop, and hence spoofing the
- cython specific rich comparison behaviour.
- """
- pass
- def __cmp__(self, other):
- raise NotImplementedError('__richcmp__')
-
- class Pass(object):
- """Dummy class with no rich comparison support whatsoever."""
- pass
-
- class Pass___cmp__(object):
- """Dummy class that delegates all comparisons."""
- def __cmp__(self, other):
- return NotImplemented
-
- # Test LHS operand comparison operator processing.
- for op, expected in [(operator.gt, '__lt__'), (operator.ge, '__le__'),
- (operator.eq, '__eq__'), (operator.ne, '__ne__'),
- (operator.lt, '__gt__'), (operator.le, '__ge__')]:
- with self.assertRaisesRegex(NotImplementedError, expected):
- op(self.date1_365_day, Rich())
-
- with self.assertRaisesRegex(NotImplementedError, '__richcmp__'):
- op(self.date1_365_day, CythonRich())
-
- # Test RHS operand comparison operator processing.
- for op in [operator.gt, operator.ge, operator.eq, operator.ne,
- operator.lt, operator.le]:
- with self.assertRaisesRegex(TypeError, 'cannot compare'):
- op(Pass(), self.date1_365_day)
-
- with self.assertRaisesRegex(TypeError, 'cannot compare'):
- op(Pass___cmp__(), self.date1_365_day)
-
-
class issue17TestCase(unittest.TestCase):
"""Regression tests for issue #17/#669."""
# issue 17 / 699: timezone formats not supported correctly