lots of gutting. purposes, input, and output were unclear in many places. still broken.
This commit is contained in:
340
notes/flatten_pseudocode.svg
Normal file
340
notes/flatten_pseudocode.svg
Normal file
@@ -0,0 +1,340 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
sodipodi:docname="flatten_pseudocode.svg"
|
||||
inkscape:version="0.47pre4 r22446"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
height="1052.3622047"
|
||||
width="744.09448819">
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="215.08492"
|
||||
inkscape:cy="417.34138"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="750"
|
||||
inkscape:window-x="-1"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1" />
|
||||
<defs
|
||||
id="defs4">
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="CurveIn"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="CurveIn">
|
||||
<path
|
||||
transform="scale(0.6)"
|
||||
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none;marker-end:none;fill:none"
|
||||
d="M 4.6254930,-5.0456926 C 1.8654930,-5.0456926 -0.37450702,-2.8056926 -0.37450702,-0.045692580 C -0.37450702,2.7143074 1.8654930,4.9543074 4.6254930,4.9543074"
|
||||
id="path3807" />
|
||||
</marker>
|
||||
<marker
|
||||
style="overflow:visible"
|
||||
id="Torso"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Torso">
|
||||
<g
|
||||
transform="scale(0.7)"
|
||||
id="g3835">
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none"
|
||||
d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
|
||||
id="path3837" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none"
|
||||
d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
|
||||
id="path3839" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
|
||||
d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
|
||||
id="path3841" />
|
||||
<rect
|
||||
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none"
|
||||
width="2.6366582"
|
||||
height="2.7608147"
|
||||
x="-10.391706"
|
||||
y="-1.7408575"
|
||||
transform="matrix(0.527536,-0.849533,0.887668,0.460484,0,0)"
|
||||
id="rect3843" />
|
||||
<rect
|
||||
style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none"
|
||||
width="2.7327356"
|
||||
height="2.8614161"
|
||||
x="4.9587269"
|
||||
y="-7.9629307"
|
||||
transform="matrix(0.671205,-0.741272,0.790802,0.612072,0,0)"
|
||||
id="rect3845" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
|
||||
sodipodi:cx="16.172634"
|
||||
sodipodi:cy="-28.685045"
|
||||
sodipodi:rx="0.60731727"
|
||||
sodipodi:ry="0.60731727"
|
||||
d="m 16.779951,-28.685045 c 0,0.335412 -0.271905,0.607317 -0.607317,0.607317 -0.335412,0 -0.607317,-0.271905 -0.607317,-0.607317 0,-0.335412 0.271905,-0.607318 0.607317,-0.607318 0.335412,0 0.607317,0.271906 0.607317,0.607318 z"
|
||||
transform="matrix(0,-1.109517,1.109517,0,25.96648,19.71619)"
|
||||
id="path3847" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
|
||||
sodipodi:cx="16.172634"
|
||||
sodipodi:cy="-28.685045"
|
||||
sodipodi:rx="0.60731727"
|
||||
sodipodi:ry="0.60731727"
|
||||
d="m 16.779951,-28.685045 c 0,0.335412 -0.271905,0.607317 -0.607317,0.607317 -0.335412,0 -0.607317,-0.271905 -0.607317,-0.607317 0,-0.335412 0.271905,-0.607318 0.607317,-0.607318 0.335412,0 0.607317,0.271906 0.607317,0.607318 z"
|
||||
transform="matrix(0,-1.109517,1.109517,0,26.82450,16.99126)"
|
||||
id="path3849" />
|
||||
</g>
|
||||
</marker>
|
||||
<marker
|
||||
style="overflow:visible;"
|
||||
id="Arrow2Send"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Send">
|
||||
<path
|
||||
transform="scale(0.3) rotate(180) translate(-2.3,0)"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
|
||||
id="path3655" />
|
||||
</marker>
|
||||
<marker
|
||||
style="overflow:visible;"
|
||||
id="Arrow2Mend"
|
||||
refX="0.0"
|
||||
refY="0.0"
|
||||
orient="auto"
|
||||
inkscape:stockid="Arrow2Mend">
|
||||
<path
|
||||
transform="scale(0.6) rotate(180) translate(0,0)"
|
||||
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
|
||||
style="font-size:12.0;fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
|
||||
id="path3649" />
|
||||
</marker>
|
||||
<inkscape:perspective
|
||||
id="perspective10"
|
||||
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
|
||||
inkscape:vp_z="744.09448 : 526.18109 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_x="0 : 526.18109 : 1"
|
||||
sodipodi:type="inkscape:persp3d" />
|
||||
</defs>
|
||||
<metadata
|
||||
id="metadata7">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:groupmode="layer"
|
||||
inkscape:label="Layer 1">
|
||||
<path
|
||||
transform="translate(20.53571,-20.178571)"
|
||||
d="m 301.02547,150.80104 a 135.36044,72.225906 0 1 1 -270.720889,0 135.36044,72.225906 0 1 1 270.720889,0 z"
|
||||
sodipodi:ry="72.225906"
|
||||
sodipodi:rx="135.36044"
|
||||
sodipodi:cy="150.80104"
|
||||
sodipodi:cx="165.66502"
|
||||
id="path2816"
|
||||
style="fill:#fcaf3e;fill-opacity:1;fill-rule:nonzero;stroke:#f57900;stroke-width:4;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
sodipodi:type="arc" />
|
||||
<g
|
||||
style="opacity:0.5"
|
||||
id="g11159">
|
||||
<path
|
||||
style="stroke-linejoin:round;opacity:1;stroke-opacity:1;fill-opacity:1;stroke-dashoffset:0;stroke:#f57900;stroke-linecap:round;stroke-miterlimit:4;stroke-width:3.99999995200000003;fill:#fcaf3e"
|
||||
d="M336.823432 178.821844C336.823432 197.284578 313.622456 212.251542 285.002616 212.251542C285.002428719 212.251542 285.002241439 212.251541999 285.00205416 212.251541997C256.38245236 212.25139846 233.18178 197.284489467 233.18178 178.821844C233.18178 178.821795704 233.18178 178.821747407 233.181780001 178.821699111C233.181881099 160.359057696 256.382818356 145.3921444 285.002616 145.3921444C285.002678356 145.3921444 285.002740712 145.3921444 285.002803068 145.3921444C313.622557099 145.392222704 336.823432 160.359184296 336.823432 178.821844C336.823432 178.821844 336.823432 178.821844 336.823432 178.821844"
|
||||
id="path11161" />
|
||||
<path
|
||||
style="stroke-linejoin:round;opacity:1;stroke-opacity:1;fill-opacity:1;stroke-dashoffset:0;stroke:#f57900;stroke-linecap:round;stroke-miterlimit:4;stroke-width:3.99999990400000005;fill:#fcaf3e"
|
||||
d="M427.169644 181.083768C427.169644 210.756636 393.204862 234.811184 351.307202 234.811184C351.30706154 234.811184 351.306921079 234.811183999 351.30678062 234.811183998C309.40928427 234.811076345 275.44473 210.7565696 275.44473 181.083768C275.44473 181.083671407 275.44473 181.083574814 275.444730001 181.083478221C275.444932198 151.410785392 309.409636712 127.3563488 351.307202 127.3563488C351.307326712 127.3563488 351.307451423 127.3563488 351.307576135 127.356348801C393.205064197 127.356505408 427.169644 151.411038593 427.169644 181.083768C427.169644 181.083768 427.169644 181.083768 427.169644 181.083768"
|
||||
id="path11163" />
|
||||
<path
|
||||
style="stroke-linejoin:round;opacity:1;stroke-opacity:1;fill-opacity:1;stroke-dashoffset:0;stroke:#f57900;stroke-linecap:round;stroke-miterlimit:4;stroke-width:3.99999985600000008;fill:#fcaf3e"
|
||||
d="M517.515856 183.345692C517.515856 224.228694 472.787268 257.370826 417.611788 257.370826C417.61169436 257.370826 417.61160072 257.370825999 417.61150708 257.370825998C362.43611618 257.37075423 317.70768 224.228649734 317.70768 183.345692C317.70768 183.345547111 317.707680001 183.345402221 317.707680002 183.345257332C317.707983297 142.462513088 362.436455068 109.3205532 417.611788 109.3205532C417.611975068 109.3205532 417.612162135 109.3205532 417.612349203 109.320553201C472.787571296 109.320788113 517.515856 142.462892889 517.515856 183.345692C517.515856 183.345692 517.515856 183.345692 517.515856 183.345692"
|
||||
id="path11165" />
|
||||
<path
|
||||
style="stroke-linejoin:round;opacity:1;stroke-opacity:1;fill-opacity:1;stroke-dashoffset:0;stroke:#f57900;stroke-linecap:round;stroke-miterlimit:4;stroke-width:3.99999980800000010;fill:#fcaf3e"
|
||||
d="M607.862068 185.607616C607.862068 237.700752 552.369674 279.930468 483.916374 279.930468C483.91632718 279.930468 483.91628036 279.930468 483.91623354 279.930467999C415.46294809 279.930432115 359.97063 237.700729867 359.97063 185.607616C359.97063 185.607422814 359.970630001 185.607229628 359.970630002 185.607036442C359.971034396 133.514240784 415.463273424 91.2847576 483.916374 91.2847576C483.916623424 91.2847576 483.916872847 91.2847576006 483.91712227 91.2847576018C552.370078395 91.2850708167 607.862068 133.514747186 607.862068 185.607616C607.862068 185.607616 607.862068 185.607616 607.862068 185.607616"
|
||||
id="path11167" />
|
||||
</g>
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text3590"
|
||||
y="119.57474"
|
||||
x="99.197487"
|
||||
style="font-size:34.49922942999999975px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Alba Super;-inkscape-font-specification:Alba Super"
|
||||
xml:space="preserve"><tspan
|
||||
y="119.57474"
|
||||
x="99.197487"
|
||||
id="tspan3592"
|
||||
sodipodi:role="line">All Zones</tspan></text>
|
||||
<path
|
||||
id="path8303"
|
||||
d="m 246.47722,176.55992 c 0,7.2526 -12.43717,13.13198 -27.77919,13.13198 -15.34203,0 -27.7792,-5.87938 -27.7792,-13.13198 0,-7.25259 12.43717,-13.13198 27.7792,-13.13198 15.34202,0 27.77919,5.87939 27.77919,13.13198 z"
|
||||
style="fill:#fcaf3e;stroke:#f57900;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dashoffset:0;stroke-opacity:1;opacity:1" />
|
||||
<path
|
||||
style="fill:#fcaf3e;stroke:#f57900;stroke-width:3.99999976000000013;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 698.20828,187.86954 c 0,63.30327 -66.2562,114.62057 -147.98732,114.62057 -81.73118,0 -147.98738,-51.3173 -147.98738,-114.62057 0,-63.30318 66.2562,-114.620578 147.98738,-114.620578 81.73112,0 147.98732,51.317398 147.98732,114.620578 z"
|
||||
id="path8306" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:34.49922943px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Alba Super;-inkscape-font-specification:Alba Super"
|
||||
x="459.19748"
|
||||
y="139.57474"
|
||||
id="text8847"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan8849"
|
||||
x="459.19748"
|
||||
y="139.57474">One Zone</tspan></text>
|
||||
<path
|
||||
id="path8851"
|
||||
d="m 658.79938,227.86954 c 0,34.11104 -48.61224,61.76343 -108.57845,61.76343 -59.96625,0 -108.57848,-27.65239 -108.57848,-61.76343 0,-34.11099 48.61223,-61.76343 108.57848,-61.76343 59.96621,0 108.57845,27.65244 108.57845,61.76343 z"
|
||||
style="fill:#8ae234;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text8853"
|
||||
y="225.57474"
|
||||
x="485.19748"
|
||||
style="font-size:34.49922943px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#2e3436;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Alba Super;-inkscape-font-specification:Alba Super"
|
||||
xml:space="preserve"><tspan
|
||||
y="225.57474"
|
||||
x="485.19748"
|
||||
id="tspan8855"
|
||||
sodipodi:role="line">Its Rules</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text8857"
|
||||
y="303.505"
|
||||
x="84.285713"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
y="303.505"
|
||||
x="84.285713"
|
||||
id="tspan8859"
|
||||
sodipodi:role="line">foreach zone</tspan><tspan
|
||||
id="tspan8871"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
y="325.505"
|
||||
x="84.285713"
|
||||
sodipodi:role="line"> get its rules</tspan></text>
|
||||
<path
|
||||
style="fill:#8ae234;stroke:#4e9a06;stroke-width:3.99999952;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 608.22795,259.86954 c 0,9.08861 -13.43461,16.45638 -30.00704,16.45638 -16.57243,0 -30.00704,-7.36777 -30.00704,-16.45638 0,-9.08861 13.43461,-16.45639 30.00704,-16.45639 16.57243,0 30.00704,7.36778 30.00704,16.45639 z"
|
||||
id="path10917" />
|
||||
<g
|
||||
id="g14587">
|
||||
<g
|
||||
id="g14668"
|
||||
style="opacity:0.39419087">
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 615.61335,282.01467 c 0,11.44061 -16.74117,20.71506 -37.39244,20.71506 -2e-5,0 -4e-5,0 -6e-5,0 -20.65124,-2e-5 -37.39238,-9.27446 -37.39238,-20.71506 0,-2e-5 0,-5e-5 0,-7e-5 7e-5,-11.44058 16.74121,-20.715 37.39244,-20.715 2e-5,0 4e-5,0 6e-5,0 20.65125,2e-5 37.39238,9.27447 37.39238,20.71507 0,0 0,0 0,0"
|
||||
id="path14601" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 623.36041,305.24427 c 0,13.9078 -20.20964,25.18229 -45.1395,25.18229 -4e-5,0 -9e-5,0 -1.3e-4,0 -24.9298,-4e-5 -45.13937,-11.27452 -45.13937,-25.18229 0,-5e-5 0,-10e-5 0,-1.5e-4 1.4e-4,-13.90773 20.20973,-25.18215 45.1395,-25.18215 4e-5,0 9e-5,0 1.3e-4,0 24.9298,4e-5 45.13937,11.27453 45.13937,25.1823 0,0 0,0 0,0"
|
||||
id="path14599" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 631.55254,329.80839 c 0,16.51672 -23.87738,29.90615 -53.33163,29.90615 -7e-5,0 -1.3e-4,0 -2e-4,0 -29.45415,-6e-5 -53.33143,-13.38947 -53.33143,-29.90615 0,-8e-5 0,-1.5e-4 0,-2.3e-4 2.2e-4,-16.51661 23.87752,-29.90594 53.33163,-29.90594 7e-5,0 1.3e-4,0 2e-4,0 29.45415,6e-5 53.33143,13.38949 53.33143,29.90617 0,0 0,0 0,0"
|
||||
id="path14597" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 640.31405,356.07981 c 0,19.30696 -27.80004,34.95834 -62.09314,34.95834 -9e-5,0 -1.8e-4,0 -2.7e-4,0 -34.29297,-8e-5 -62.09287,-15.65143 -62.09287,-34.95834 0,-1.1e-4 0,-2.1e-4 0,-3.1e-4 2.9e-4,-19.30683 27.80023,-34.95806 62.09314,-34.95806 9e-5,0 1.8e-4,0 2.7e-4,0 34.29297,8e-5 62.09287,15.65145 62.09287,34.95837 0,0 0,0 0,0"
|
||||
id="path14595" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999951999999981;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 649.8469,384.6641 c 0,22.34286 -32.06805,40.45532 -71.62599,40.45532 -1.2e-4,0 -2.4e-4,0 -3.5e-4,0 -39.55778,-1.1e-4 -71.62564,-18.11253 -71.62564,-40.45532 0,-1.4e-4 0,-2.7e-4 0,-4.1e-4 3.8e-4,-22.34268 32.06829,-40.45495 71.62599,-40.45495 1.2e-4,0 2.4e-4,0 3.5e-4,0 39.55779,1.1e-4 71.62564,18.11256 71.62564,40.45536 0,0 0,0 0,0"
|
||||
id="path14593" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999927999999993;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 660.52703,416.68848 c 0,25.74412 -36.84971,46.61385 -82.30612,46.61385 -1.5e-4,0 -3e-4,0 -4.4e-4,0 -45.45621,-1.3e-4 -82.30568,-20.86981 -82.30568,-46.61385 0,-1.7e-4 0,-3.4e-4 0,-5.1e-4 4.8e-4,-25.7439 36.85001,-46.61338 82.30612,-46.61338 1.5e-4,0 3e-4,0 4.4e-4,0 45.45621,1.4e-4 82.30568,20.86984 82.30568,46.61389 0,0 0,0 0,0"
|
||||
id="path14591" />
|
||||
<path
|
||||
style="opacity:1;fill:#8ae234;fill-opacity:1;stroke:#4e9a06;stroke-width:3.99999927999999993;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0"
|
||||
d="m 673.2604,454.86955 c 0,29.79928 -42.55062,53.95636 -95.03949,53.95636 -1.8e-4,0 -3.7e-4,0 -5.5e-4,0 -52.48861,-1.7e-4 -95.03894,-24.15719 -95.03894,-53.95636 0,-2.1e-4 0,-4.2e-4 0,-6.3e-4 5.9e-4,-29.799 42.551,-53.95578 95.03949,-53.95578 1.8e-4,0 3.7e-4,0 5.5e-4,0 52.48861,1.7e-4 95.03894,24.15722 95.03894,53.95641 0,0 0,0 0,0"
|
||||
id="path14589" />
|
||||
</g>
|
||||
</g>
|
||||
<path
|
||||
id="path11235"
|
||||
d="m 694.93789,507.86955 c 0,36.70284 -52.25597,66.45636 -116.71698,66.45636 -64.461,0 -116.71698,-29.75352 -116.71698,-66.45636 0,-36.70285 52.25598,-66.45641 116.71698,-66.45641 64.46101,0 116.71698,29.75356 116.71698,66.45641 z"
|
||||
style="fill:#8ae234;stroke:#4e9a06;stroke-width:3.99999928;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:0" />
|
||||
<text
|
||||
sodipodi:linespacing="100%"
|
||||
id="text11237"
|
||||
y="501.50504"
|
||||
x="492"
|
||||
style="font-size:34px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#030303;fill-opacity:1;fill-rule:nonzero;stroke:none;font-family:Alba Super;-inkscape-font-specification:Alba Super"
|
||||
xml:space="preserve"><tspan
|
||||
y="501.50504"
|
||||
x="492"
|
||||
id="tspan11239"
|
||||
sodipodi:role="line">One Rule</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#4e9a06;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
x="64.285713"
|
||||
y="443.505"
|
||||
id="text14677"
|
||||
sodipodi:linespacing="100%"><tspan
|
||||
sodipodi:role="line"
|
||||
x="64.285713"
|
||||
y="443.505"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
id="tspan14681">foreach rule and zone</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="64.285713"
|
||||
y="465.505"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
id="tspan14687"> convert datetime to UTC</tspan><tspan
|
||||
sodipodi:role="line"
|
||||
x="64.285713"
|
||||
y="487.505"
|
||||
style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Andale Mono;-inkscape-font-specification:Andale Mono"
|
||||
id="tspan2874"> -using zoneinfo</tspan></text>
|
||||
<path
|
||||
style="fill:none;stroke:#f57900;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:30,30;stroke-dashoffset:0"
|
||||
d="M 447.14286,259.50504 C 439.90168,446.30825 427.1765,614.16673 378.57143,658.07647"
|
||||
id="path2876"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
id="path3695"
|
||||
d="M 538.57143,546.64789 C 486.40259,543.20247 425.55741,569.59524 400.00001,648.07647"
|
||||
style="fill:none;stroke:#4e9a06;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:30, 30;stroke-dashoffset:0" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 23 KiB |
40
src/ezic.erl
40
src/ezic.erl
@@ -4,22 +4,16 @@
|
||||
-export([
|
||||
localtime/1
|
||||
, utc_to_local/2
|
||||
% , local_to_utc/2
|
||||
% , zone_convert/3
|
||||
, next_timechange/1
|
||||
, next_timechange/2
|
||||
, next_timechange_after/2
|
||||
]).
|
||||
|
||||
-export([load/1, dev_start/0, test/0]).
|
||||
|
||||
|
||||
-define(gs2dt(X), calendar:gregorian_seconds_to_datetime(X)).
|
||||
-define(dt2gs(X), calendar:datetime_to_gregorian_seconds(X)).
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% API
|
||||
% PUBLIC API
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
@@ -27,30 +21,17 @@
|
||||
localtime(TzName) ->
|
||||
utc_to_local(erlang:universaltime(), TzName).
|
||||
|
||||
|
||||
utc_to_local(UTCDatetime, TzName) ->
|
||||
{ok, Zone, Rule}= current_as_of_utc(UTCDatetime, TzName),
|
||||
SecDiff= time_offset(Zone, Rule),
|
||||
date_add(UTCDatetime, SecDiff).
|
||||
|
||||
|
||||
%% local_to_utc(Datetime, TzName) ->
|
||||
%% {ok, Zone, Rule}= current_as_of_local(Datetime, TzName),
|
||||
%% SecDiff= time_offset(Zone, Rule),
|
||||
%% date_subtract(Datetime, SecDiff).
|
||||
|
||||
|
||||
%% zone_convert(Datetime, FromTimeZone, ToTimeZone) ->
|
||||
%% UTC= local_to_utc(Datetime, FromTimeZone),
|
||||
%% utc_to_local(UTC, ToTimeZone).
|
||||
ezic_date:add_seconds(UTCDatetime, SecDiff).
|
||||
|
||||
|
||||
|
||||
next_timechange(TzName) ->
|
||||
next_timechange(erlang:universaltime(), TzName).
|
||||
next_timechange_after(erlang:universaltime(), TzName).
|
||||
|
||||
next_timechange(UTCDatetime, TzName) ->
|
||||
UTCDatetime, TzName,
|
||||
next_timechange_after(_UTCDatetime, _TzName) ->
|
||||
not_done.
|
||||
|
||||
|
||||
@@ -64,8 +45,7 @@ next_timechange(UTCDatetime, TzName) ->
|
||||
|
||||
|
||||
load(Folder) ->
|
||||
ezic_loader:load(Folder),
|
||||
ezic_flatten:flatten().
|
||||
ezic_loader:load(Folder).
|
||||
|
||||
|
||||
dev_start() ->
|
||||
@@ -103,11 +83,3 @@ time_offset(Zone, Rule) ->
|
||||
DSTSec= ezic_rule:dst_sec(Rule),
|
||||
OffsetSec + DSTSec.
|
||||
|
||||
|
||||
|
||||
date_add(Datetime, SecDiff) ->
|
||||
?gs2dt(?dt2gs(Datetime) + SecDiff).
|
||||
|
||||
%% date_subtract(Datetime, SecDiff) ->
|
||||
%% ?gs2dt(?dt2gs(Datetime) - SecDiff).
|
||||
|
||||
|
||||
@@ -1,86 +1,52 @@
|
||||
-module(ezic_date).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
|
||||
-ifdef(TEST).
|
||||
-compile([export_all]).
|
||||
-endif.
|
||||
-export([
|
||||
% rule-specific
|
||||
for_rule/2
|
||||
, for_rule_zone/3
|
||||
|
||||
|
||||
% converters
|
||||
, month_to_num/1
|
||||
, day_to_num/1
|
||||
|
||||
|
||||
% date math
|
||||
, add_seconds/2
|
||||
, all_times/3
|
||||
]).
|
||||
|
||||
|
||||
|
||||
|
||||
-export([for/2]).
|
||||
-export([month_to_num/1, day_to_num/1]).
|
||||
-export([compare_times/2, compare_datetimes/2, normalize/1, overlap/2, date_between/2]).
|
||||
|
||||
-export([add_seconds/2, all_times/3]).
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PUBLIC API
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% returns the date tuple for a given rule and year
|
||||
% same for all timezones.
|
||||
% e.g. -> {Y,M,D}
|
||||
for(#rule{in=M, on={last, D}}, Y) ->
|
||||
% returns {Y,M,D} for a rule and Year
|
||||
for_rule(#rule{in=M, on={last, D}}, Y) ->
|
||||
last_day_of(D, Y,M);
|
||||
for(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) ->
|
||||
for_rule(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, Y) ->
|
||||
first_day_limited(Day, Filter, Y,M).
|
||||
|
||||
|
||||
% returns the date on which the last Day (sun,mon,tue,etc.) occurs in a given month/year
|
||||
% same for all timezones
|
||||
last_day_of(Day, Y,M) ->
|
||||
LastDay= calendar:last_day_of_the_month(Y,M),
|
||||
previous_day(Day, {Y,M,LastDay}).
|
||||
|
||||
|
||||
% returns a date tuple {Y,M,D} representing the first available date, given the filter
|
||||
% same for all timezones
|
||||
first_day_limited(Day, {geq, N}, Y,M) ->
|
||||
next_day(Day, {Y,M,N});
|
||||
first_day_limited(Day, {leq, N}, Y,M) ->
|
||||
previous_day(Day, {Y,M,N}).
|
||||
% for_rule(#rule{}, Zone, Year) -> {WallTime, STDTime, UTCTime}
|
||||
% returns the date set for a given rule and year
|
||||
% same for all timezones.
|
||||
for_rule_zone(#rule{in=M, on={last, D}, at=_Time, save=_DSTOffset}, _Zone=#zone{gmtoff=_Offset}, Y) ->
|
||||
_LDO= last_day_of(D, Y,M),
|
||||
|
||||
not_done;
|
||||
for_rule_zone(#rule{in=M, on=#tzon{day=Day, filter=Filter}}, _Zone, Y) ->
|
||||
first_day_limited(Day, Filter, Y,M),
|
||||
|
||||
|
||||
% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs BEFORE the given date.
|
||||
% same for all timezones
|
||||
previous_day(Day, Date={Y,M,D}) ->
|
||||
Daynum= day_to_num(Day),
|
||||
LeqDoW= calendar:day_of_the_week(Date),
|
||||
case Daynum=:=LeqDoW of
|
||||
true -> Date;
|
||||
_ ->
|
||||
DayDiff= case LeqDoW-Daynum < 0 of
|
||||
true -> LeqDoW-Daynum+7;
|
||||
_ -> LeqDoW-Daynum
|
||||
end,
|
||||
case D-DayDiff < 0 of
|
||||
true -> erlang:error(no_previous_day, [Day, Date]);
|
||||
false -> {Y,M,D-DayDiff}
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs AFTER the given date.
|
||||
% same for all timezones
|
||||
next_day(Day, Date={Y,M,D}) ->
|
||||
Daynum= day_to_num(Day),
|
||||
LeqDoW= calendar:day_of_the_week(Date),
|
||||
case Daynum=:=LeqDoW of
|
||||
true -> Date;
|
||||
_ ->
|
||||
DayDiff= case Daynum-LeqDoW < 0 of
|
||||
true -> Daynum-LeqDoW+7;
|
||||
_ -> Daynum-LeqDoW
|
||||
end,
|
||||
case D+DayDiff > calendar:last_day_of_the_month(Y,M) of
|
||||
true -> erlang:error(no_next_day, [Day, Date]);
|
||||
false -> {Y,M,D+DayDiff}
|
||||
end
|
||||
end.
|
||||
not_done.
|
||||
|
||||
|
||||
|
||||
@@ -107,127 +73,18 @@ day_to_num("Thu") -> 4;
|
||||
day_to_num("Fri") -> 5;
|
||||
day_to_num("Sat") -> 6;
|
||||
day_to_num("Sun") -> 7;
|
||||
day_to_num(_) -> -1.
|
||||
|
||||
|
||||
|
||||
compare_datetimes(DT1, DT2) ->
|
||||
NDT1= normalize(DT1),
|
||||
NDT2= normalize(DT2),
|
||||
compare_datetimes_normal(NDT1, NDT2).
|
||||
|
||||
|
||||
compare_datetimes_normal(minimum, _) -> true;
|
||||
compare_datetimes_normal(_, maximum) -> true;
|
||||
|
||||
|
||||
compare_datetimes_normal(current, current) -> true;
|
||||
compare_datetimes_normal(current, _) -> false;
|
||||
compare_datetimes_normal(_,current) -> true;
|
||||
|
||||
% @bug this is not true if the times are from different time zones
|
||||
% @todo check types for D1 and D2
|
||||
compare_datetimes_normal({D1, _}, {D2, _}) when D1 < D2 ->
|
||||
true;
|
||||
compare_datetimes_normal({D1, _}, {D2, _}) when D1 > D2 ->
|
||||
false;
|
||||
compare_datetimes_normal({_, T1}, {_, T2}) ->
|
||||
compare_times(T1, T2).
|
||||
|
||||
|
||||
compare_times(TZ1=#tztime{}, TZ2=#tztime{}) ->
|
||||
{NT1, NT2} = time_equalize(TZ1, TZ2),
|
||||
NT1 =< NT2;
|
||||
compare_times(Tz1, Tz2) ->
|
||||
erlang:error(wtf_not_done, [Tz1, Tz2]).
|
||||
|
||||
|
||||
|
||||
time_equalize(#tztime{time=T1, flag=F1}, #tztime{time=T2, flag=F2}) when F1=:=F2 ->
|
||||
{T1, T2};
|
||||
time_equalize(T1, T2) ->
|
||||
%@todo this may be difficult. gotta do it!
|
||||
erlang:error(wtf_not_done, T1, T2).
|
||||
|
||||
|
||||
|
||||
normalize(current) -> current;
|
||||
normalize(only) -> only;
|
||||
normalize(maximum) -> maximum;
|
||||
normalize(minimum) -> minimum;
|
||||
|
||||
|
||||
normalize(Y) when is_integer(Y) ->
|
||||
{{Y,1,1}, #tztime{}};
|
||||
normalize(Date={_,_,D}) when is_integer(D) ->
|
||||
{Date, #tztime{}};
|
||||
normalize({Y,M,{last, D}}) ->
|
||||
Date=last_day_of(D, Y,M),
|
||||
{Date, #tztime{}};
|
||||
|
||||
|
||||
normalize({Date={_,_,_},Time={H,_,_}}) when is_integer(H) ->
|
||||
{Date, #tztime{time=Time}};
|
||||
|
||||
normalize({Date={_,_,D}, Tz=#tztime{}}) when is_integer(D) ->
|
||||
{Date, Tz};
|
||||
normalize({{Y,M,#tzon{day=Day, filter=Filter}}, Tz=#tztime{}}) ->
|
||||
Date= first_day_limited(Day, Filter, Y,M),
|
||||
{Date, Tz};
|
||||
normalize({{Y,M,{last, D}}, Tz=#tztime{}}) ->
|
||||
Date=last_day_of(D, Y,M),
|
||||
{Date, Tz};
|
||||
normalize(X) ->
|
||||
?debug("normalize: ~p", [X]),
|
||||
erlang:error(wtf_not_done, X).
|
||||
|
||||
|
||||
|
||||
|
||||
overlap({D1s,D1e}, {D2s,D2e}) ->
|
||||
D1sN= normalize(D1s),
|
||||
D1eN= normalize(D1e),
|
||||
D2sN= normalize(D2s),
|
||||
D2eN= normalize(D2e),
|
||||
dates_overlap_normal({D1sN,D1eN}, {D2sN,D2eN}).
|
||||
|
||||
|
||||
dates_overlap_normal({D1s,D1e}, {D2s,D2e}) ->
|
||||
date_between_normal(D1s, {D2s,D2e})
|
||||
orelse date_between_normal(D1e, {D2s,D2e}).
|
||||
|
||||
|
||||
date_between(D1, {D2s, D2e}) ->
|
||||
D1N= normalize(D1),
|
||||
D2sN= normalize(D2s),
|
||||
D2eN= normalize(D2e),
|
||||
date_between_normal(D1N, {D2sN, D2eN}).
|
||||
|
||||
|
||||
date_between_normal(minimum, {minimum,_}) -> true;
|
||||
date_between_normal(minimum, {_,_}) -> false;
|
||||
|
||||
date_between_normal(maximum, {_, maximum}) -> true;
|
||||
date_between_normal(maximum, {_,_}) -> false;
|
||||
|
||||
date_between_normal(only, _) -> false;
|
||||
date_between_normal(current, {_, current}) -> true;
|
||||
date_between_normal(current, {_, End}) when End =/= current -> false;
|
||||
date_between_normal(D1, {D2, only}) ->
|
||||
{{Y1,_,_},_}=D1,
|
||||
{{Y2,_,_},_}=D2,
|
||||
Y1 =:= Y2;
|
||||
date_between_normal(D1, {D2s, D2e}) ->
|
||||
compare_datetimes_normal(D2s, D1)
|
||||
andalso compare_datetimes_normal(D1, D2e).
|
||||
|
||||
day_to_num(X) -> erlang:error(badday, X).
|
||||
|
||||
|
||||
|
||||
add_seconds(Datetime, Seconds) ->
|
||||
try
|
||||
calendar:gregorian_seconds_to_datetime(
|
||||
calendar:date_to_gregorian_seconds(Datetime) + Seconds
|
||||
).
|
||||
calendar:datetime_to_gregorian_seconds(Datetime) + Seconds
|
||||
)
|
||||
catch
|
||||
error:Reason -> erlang:error(baddate, Datetime)
|
||||
end.
|
||||
|
||||
|
||||
|
||||
@@ -237,7 +94,7 @@ add_seconds(Datetime, Seconds) ->
|
||||
% where each is a datetime tuple: {{Y,M,D}{HH,MM,SS}}
|
||||
|
||||
% universal time given
|
||||
all_times(Datetime=#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset)
|
||||
all_times(#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset)
|
||||
when Flag=:=u; Flag=:=g; Flag=:=z ->
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
@@ -249,7 +106,7 @@ all_times(Datetime=#tztime{time=UTCTime, flag=Flag}, Offset, DSTOffset)
|
||||
|
||||
|
||||
% standard time given
|
||||
all_times(Datetime=#tztime{time=STDTime, flag=s}, Offset, DSTOffset) ->
|
||||
all_times(#tztime{time=STDTime, flag=s}, Offset, DSTOffset) ->
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
|
||||
@@ -260,7 +117,7 @@ all_times(Datetime=#tztime{time=STDTime, flag=s}, Offset, DSTOffset) ->
|
||||
|
||||
|
||||
% wall time given
|
||||
all_times(Datetime=#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset)
|
||||
all_times(#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset)
|
||||
when Flag=:=w, Flag=:=undefined ->
|
||||
OSec= calendar:time_to_seconds(Offset),
|
||||
DSTSec= calendar:time_to_seconds(DSTOffset),
|
||||
@@ -271,3 +128,93 @@ all_times(Datetime=#tztime{time=WallTime, flag=Flag}, Offset, DSTOffset)
|
||||
{WallTime, STDTime, UTCTime}.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
% last_day_of(Day, Y,M) -> {Y,M,D}
|
||||
% returns the date on which the last Day (sun,mon,tue,etc.) occurs in a given month/year
|
||||
% same for all timezones
|
||||
last_day_of(Day, Y,M) ->
|
||||
LastDay= calendar:last_day_of_the_month(Y,M),
|
||||
previous_day(Day, {Y,M,LastDay}).
|
||||
|
||||
|
||||
% returns a date tuple {Y,M,D} representing the first available date, given the filter
|
||||
% same for all timezones
|
||||
first_day_limited(Day, {geq, N}, Y,M) ->
|
||||
next_day(Day, {Y,M,N});
|
||||
first_day_limited(Day, {leq, N}, Y,M) ->
|
||||
previous_day(Day, {Y,M,N}).
|
||||
|
||||
|
||||
|
||||
% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs BEFORE the given date.
|
||||
% same for all timezones
|
||||
previous_day(Day, Date) ->
|
||||
Daynum= day_to_num(Day),
|
||||
LeqDoW= calendar:day_of_the_week(Date),
|
||||
case Daynum=:=LeqDoW of
|
||||
true -> Date;
|
||||
_ ->
|
||||
DayDiff= day_diff(LeqDoW, Daynum),
|
||||
add_days_in_month(-DayDiff, Date)
|
||||
end.
|
||||
|
||||
|
||||
% Returns the soonest date on which Day (sun/mon/tue/etc.) occurs AFTER the given date.
|
||||
% same for all timezones
|
||||
next_day(Day, Date) ->
|
||||
Daynum= day_to_num(Day),
|
||||
LeqDoW= calendar:day_of_the_week(Date),
|
||||
case Daynum=:=LeqDoW of
|
||||
true -> Date;
|
||||
_ ->
|
||||
DayDiff= day_diff(Daynum, LeqDoW),
|
||||
add_days_in_month(DayDiff, Date)
|
||||
end.
|
||||
|
||||
|
||||
% returns absolute number of days until the next day-of-the-week,
|
||||
% given some current day-of-the-week.
|
||||
day_diff(From, To) ->
|
||||
case From - To < 0 of
|
||||
true -> From - To + 7;
|
||||
_ -> From - To
|
||||
end.
|
||||
|
||||
|
||||
% adds/subtracts days within a month
|
||||
% errors-out if arguments require change of month
|
||||
add_days_in_month(Days, Date={Y,M,D}) ->
|
||||
case D+Days < 1 of
|
||||
true -> erlang:error(no_previous_day, {Days, Date});
|
||||
_ ->
|
||||
case D+Days > calendar:last_day_of_the_month(Y,M) of
|
||||
true -> erlang:error(no_next_day, {Days, Date});
|
||||
_ -> {Y,M,D+Days}
|
||||
end
|
||||
end.
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
normalize(_Datetime) ->
|
||||
not_done.
|
||||
|
||||
compare_normal(_DT1, _DT2) ->
|
||||
not_done.
|
||||
|
||||
|
||||
@@ -74,11 +74,7 @@ flatten_zones([Z1|_]= AllZones, Flats) ->
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
% takes zones one-by-one, gathering relevant rules and create flat periods of the same gmt offset (#flatzone)
|
||||
% takes zones one-by-one, gathering relevant rules and creating flat periods of the same gmt offset (#flatzone)
|
||||
flatten_zone_set(Zones) ->
|
||||
flatten_zone_set(?MINFLAT, Zones, []).
|
||||
|
||||
@@ -91,20 +87,20 @@ flatten_zone_set(Zones) ->
|
||||
% assumes a new zone every time it is called
|
||||
flatten_zone_set(_, [], Flats) ->
|
||||
Flats;
|
||||
flatten_zone_set(FromTimeStub, [Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | RestZones] = Zones, Flats) ->
|
||||
flatten_zone_set(FromTimeStub, [Z1=#zone{rule=RuleName, until=UntilTime, gmtoff=Offset} | _RestZones] = _Zones, _Flats) ->
|
||||
|
||||
%% we have a flatzone with start times, we populate the base offset
|
||||
FromTime= FromTimeStub#flatzone{offset=Offset},
|
||||
|
||||
|
||||
|
||||
%% we gather all rules that _may_ apply (same year)
|
||||
Rules= ezic_db:rules(RuleName),
|
||||
RelevantRules= ezic_rule:filter(FromTime, UntilTime, Rules),
|
||||
SortedRules= lists:sort(fun ezic_rule:sort_ascending/2, RelevantRules),
|
||||
|
||||
|
||||
%% Then we plot points, bouncing from rule to rule, ending when the zone ends
|
||||
{ok, NextFromTimeStub, NewFlats}= flatten_zone(FromTime, Z1, SortedRules),
|
||||
{ok, _NextFromTimeStub, _NewFlats}= flatten_zone(FromTime, Z1, SortedRules),
|
||||
|
||||
|
||||
not_done.
|
||||
|
||||
@@ -10,10 +10,10 @@ load(File) ->
|
||||
true -> {ok, parse_dir(File)};
|
||||
false -> case filelib:is_regular(File) of
|
||||
true -> {ok, parse_file(File)};
|
||||
false -> {error, {badFile, File}}
|
||||
false -> erlang:error(badFile, File)
|
||||
end
|
||||
end,
|
||||
{ok, Zones, Rules, Leaps, Links} = ezic_compile:separate(Records),
|
||||
{ok, Zones, Rules, Leaps, Links} = ezic_record:separate(Records),
|
||||
|
||||
ezic_db:wipe(),
|
||||
ezic_db:init(),
|
||||
@@ -27,12 +27,11 @@ load(File) ->
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
% returns a list of tzdata records for all files in folder
|
||||
@@ -56,21 +55,18 @@ parse_lines(eof, _, Records) ->
|
||||
parse_lines({ok, Line}, File, Records) ->
|
||||
StrLine= clean_line(Line),
|
||||
NewRecords= case length(StrLine) > 0 of
|
||||
false -> Records;
|
||||
true -> [parse_to_record(StrLine, File, Records) | Records]
|
||||
true -> [parse_to_record(StrLine, File, Records) | Records];
|
||||
false -> Records
|
||||
end,
|
||||
parse_lines(file:read_line(File), File, NewRecords).
|
||||
|
||||
|
||||
|
||||
% the Line has data, so we parse it, build a record, and return it
|
||||
parse_to_record(Line, File, Records) ->
|
||||
parse_to_record(Line, _, Records) ->
|
||||
[Type | Data] = string:tokens(Line, " \t"),
|
||||
{ok, PrevType, PrevName} = prev_rec_type(Records),
|
||||
{ok, Record} = build_record(Type, Data, {PrevType, PrevName}),
|
||||
|
||||
% parse_lines(file:read_line(File), File, [Record|Records]).
|
||||
|
||||
Record.
|
||||
|
||||
|
||||
@@ -88,10 +84,12 @@ prev_rec_type(List) when is_list(List) ->
|
||||
|
||||
|
||||
clean_line(Line) ->
|
||||
%% remove spaces, newlines, and tabs
|
||||
Line1= string:strip(Line),
|
||||
Line2= string:strip(Line1, both, $\n),
|
||||
Line3= string:strip(Line2, both, $\t),
|
||||
|
||||
%% remove comments and return
|
||||
FinalLine=Line3,
|
||||
CPos= string:chr(FinalLine, $#),
|
||||
case CPos of
|
||||
@@ -102,18 +100,18 @@ clean_line(Line) ->
|
||||
|
||||
|
||||
build_record("Rule", Data,_) ->
|
||||
ezic_record:rule(Data);
|
||||
ezic_rule:parse(Data);
|
||||
build_record("Zone", Data,_) ->
|
||||
ezic_record:zone(Data);
|
||||
ezic_zone:parse(Data);
|
||||
build_record("Link", Data,_) ->
|
||||
ezic_record:link(Data);
|
||||
build_record(GmtOff, Data, {"Zone", PrevName}) ->
|
||||
ezic_record:zone([PrevName,GmtOff|Data]);
|
||||
build_record("Leap", Data,_) ->
|
||||
ezic_record:leap(Data);
|
||||
build_record(GmtOff, Data, {"Zone", PrevName}) ->
|
||||
ezic_zone:parse([PrevName,GmtOff|Data]);
|
||||
|
||||
build_record(Type, Data, PT) ->
|
||||
{error, {badLine, Type, Data, PT}}.
|
||||
erlang:error(badLine, {Type, Data, PT}).
|
||||
|
||||
|
||||
|
||||
|
||||
162
src/ezic_parse.erl
Normal file
162
src/ezic_parse.erl
Normal file
@@ -0,0 +1,162 @@
|
||||
-module(ezic_parse).
|
||||
-include("include/ezic.hrl").
|
||||
|
||||
|
||||
-export([
|
||||
year/1
|
||||
, day_pattern/1
|
||||
, time/1
|
||||
, time_val/1
|
||||
, until/1
|
||||
, tz_abbr/1
|
||||
]).
|
||||
|
||||
|
||||
|
||||
% year(string) to year(int|atom)
|
||||
year("minimum") -> minimum;
|
||||
year("min") -> minimum;
|
||||
year("maximum") -> maximum;
|
||||
year("max") -> maximum;
|
||||
year("only") -> only;
|
||||
year(X) ->
|
||||
list_to_integer(X).
|
||||
|
||||
|
||||
|
||||
% X=last(Mon,Tue,Wed,...,Sun) -> {last, (Mon,Tue,Web,...,Sun)}
|
||||
day_pattern(X=[$l,$a,$s,$t|Day]) ->
|
||||
case ezic_date:day_to_num(Day) > 0 of
|
||||
true -> {last, Day};
|
||||
false -> erlang:error(badday,X)
|
||||
end;
|
||||
% X=(Mon,Tue,Wed,...,Sun)[<>]=int().
|
||||
day_pattern(X=[D,A,Y, Sign,$= | IntS]) ->
|
||||
Int=list_to_integer(IntS),
|
||||
Day=[D,A,Y],
|
||||
{ok, FSign}= sign(Sign),
|
||||
|
||||
case ezic_date:day_to_num(Day) > 0 of
|
||||
true -> #tzon{day=Day, filter={FSign, Int}};
|
||||
false -> erlang:error(badday, X)
|
||||
end;
|
||||
% X=int()
|
||||
day_pattern(X) ->
|
||||
list_to_integer(X).
|
||||
|
||||
|
||||
|
||||
|
||||
time_val(Str) ->
|
||||
#tztime{time=Time}= time(Str),
|
||||
Time.
|
||||
|
||||
time("-") ->
|
||||
#tztime{time={0,0,0}};
|
||||
time(TS) ->
|
||||
{Flag, RTime} = time_flag(TS),
|
||||
Time= time_abs(RTime),
|
||||
#tztime{time=Time, flag=Flag}.
|
||||
|
||||
|
||||
|
||||
until([]) ->
|
||||
current;
|
||||
until([YS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
{Y,1,1};
|
||||
until([YS,MS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
{Y,M,1};
|
||||
until([YS,MS,DS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
D= day_pattern(DS),
|
||||
{Y,M,D};
|
||||
until([YS,MS,DS,TS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
D= day_pattern(DS),
|
||||
{{Y,M,D},ezic_parse:time(TS)}.
|
||||
|
||||
|
||||
|
||||
|
||||
tz_abbr(Format) ->
|
||||
tz_abbr(Format, string:str(Format, "%s")).
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
time_flag(TS) ->
|
||||
{F, RTime}= time_flag_rev(lists:reverse(TS)),
|
||||
{F, lists:reverse(RTime)}.
|
||||
|
||||
|
||||
% absolute time string (no relativity modifiers)
|
||||
% e.g. 08:01:03
|
||||
time_abs(Time) ->
|
||||
TTok= string:tokens(Time, ":"),
|
||||
time_tokens(TTok).
|
||||
|
||||
|
||||
time_tokens([HS]) ->
|
||||
H= list_to_integer(HS),
|
||||
{H,0,0};
|
||||
time_tokens([HS,MS]) ->
|
||||
H= list_to_integer(HS),
|
||||
M= list_to_integer(MS),
|
||||
{H,M,0};
|
||||
time_tokens([HS,MS,SS]) ->
|
||||
H= list_to_integer(HS),
|
||||
M= list_to_integer(MS),
|
||||
S= list_to_integer(SS),
|
||||
{H,M,S};
|
||||
time_tokens(X) ->
|
||||
erlang:error(badtime, X).
|
||||
|
||||
|
||||
|
||||
|
||||
sign($>) -> {ok, geq};
|
||||
sign($<) -> {ok, leq}.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
time_flag_rev([F|RTime]) when F =:= $s; F =:= $w; F =:= $u ->
|
||||
{list_to_atom([F]), RTime};
|
||||
time_flag_rev([F|RTime]) when F =:= $g; F =:= $z ->
|
||||
{u, RTime};
|
||||
time_flag_rev(X=[F|_]) when F-48 < 0; F-48 > 9 ->
|
||||
erlang:error(badtime, lists:reverse(X));
|
||||
time_flag_rev(RTime) ->
|
||||
{undefined, RTime}.
|
||||
|
||||
|
||||
|
||||
tz_abbr(Format, 0) ->
|
||||
Format;
|
||||
tz_abbr(Format, Pos) ->
|
||||
First=string:substr(Format, 1, Pos-1),
|
||||
Last=string:substr(Format, Pos+2),
|
||||
string:concat(First, [$~, $s|Last]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,36 +8,14 @@
|
||||
-endif.
|
||||
|
||||
|
||||
-export([rule/1,zone/1,link/1,leap/1, separate/1]).
|
||||
-export([
|
||||
link/1
|
||||
, leap/1
|
||||
, separate/1
|
||||
]).
|
||||
|
||||
|
||||
|
||||
rule([Name,FromS,ToS,Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
From= parse_from(FromS),
|
||||
To= parse_to(ToS),
|
||||
% @todo handle year types
|
||||
In= ezic_date:month_to_num(InS),
|
||||
On= parse_on(OnS),
|
||||
At=parse_at(AtS),
|
||||
Save=parse_save(SaveS),
|
||||
|
||||
{ok, #rule{
|
||||
name=Name, from=From, to=To, type=Type,
|
||||
in=In, on=On, at=At, save=Save, letters=Letters
|
||||
}}.
|
||||
|
||||
|
||||
zone([Name,GmtOffS,Rule,FormatS | UntilTokens]) ->
|
||||
GmtOff=parse_time(GmtOffS),
|
||||
Until = parse_until(UntilTokens),
|
||||
Format= convert_format(FormatS),
|
||||
|
||||
{ok, #zone{
|
||||
name=Name, gmtoff=GmtOff, rule=Rule,
|
||||
format=Format, until=Until
|
||||
}}.
|
||||
|
||||
|
||||
link([From,To]) ->
|
||||
{ok, #link{from=From, to=To}}.
|
||||
|
||||
@@ -47,7 +25,7 @@ leap([YearS, MonthS, DayS, TimeS, Corr, RS]) ->
|
||||
Y= list_to_integer(YearS),
|
||||
M= ezic_date:month_to_num(MonthS),
|
||||
D= list_to_integer(DayS),
|
||||
Time=parse_abs_time(TimeS),
|
||||
Time= ezic_parse:time_val(TimeS),
|
||||
{ok, #leap{datetime={{Y,M,D}, Time}, corr=Corr, rs=RS}}.
|
||||
|
||||
|
||||
@@ -61,153 +39,3 @@ separate(Records) ->
|
||||
{ok, Zones, Rules, Leaps, Links}.
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% PRIVATE
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
parse_from(X) when X=:="maximum";X=:="max" ->
|
||||
maximum;
|
||||
parse_from(X) when X=:="minimum";X=:="min" ->
|
||||
minimum;
|
||||
parse_from(Year) ->
|
||||
list_to_integer(Year).
|
||||
|
||||
|
||||
|
||||
parse_to("only") ->
|
||||
only;
|
||||
parse_to(Other) ->
|
||||
parse_from(Other).
|
||||
|
||||
|
||||
|
||||
parse_on(X=[$l,$a,$s,$t|Day]) ->
|
||||
case ezic_date:day_to_num(Day) > 0 of
|
||||
true -> {last, Day};
|
||||
false -> erlang:error(badday,X)
|
||||
end;
|
||||
parse_on(X=[D,A,Y, Sign,$= | IntS]) ->
|
||||
Int=list_to_integer(IntS),
|
||||
Day=[D,A,Y],
|
||||
{ok, FSign} =parse_on_sign(Sign),
|
||||
|
||||
case ezic_date:day_to_num(Day) > 0 of
|
||||
true -> #tzon{day=Day, filter={FSign, Int}};
|
||||
false -> erlang:error(badday, X)
|
||||
end;
|
||||
parse_on(X) ->
|
||||
list_to_integer(X).
|
||||
|
||||
|
||||
parse_until([]) ->
|
||||
current;
|
||||
parse_until([YS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
{Y,1,1};
|
||||
parse_until([YS,MS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
{Y,M,1};
|
||||
parse_until([YS,MS,DS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
D= parse_on(DS),
|
||||
{Y,M,D};
|
||||
parse_until([YS,MS,DS,TS]) ->
|
||||
Y= list_to_integer(YS),
|
||||
M= ezic_date:month_to_num(MS),
|
||||
D= parse_on(DS),
|
||||
{{Y,M,D},parse_time(TS)}.
|
||||
|
||||
|
||||
|
||||
parse_at(X) ->
|
||||
parse_time(X).
|
||||
|
||||
|
||||
|
||||
parse_save("-") ->
|
||||
parse_time("-");
|
||||
parse_save(X) ->
|
||||
XRev=lists:reverse(X),
|
||||
parse_save_rev(XRev).
|
||||
|
||||
|
||||
|
||||
parse_time("-") ->
|
||||
#tztime{time={0,0,0}};
|
||||
parse_time(TS) ->
|
||||
parse_time_rev(lists:reverse(TS)).
|
||||
|
||||
|
||||
parse_abs_time(T) ->
|
||||
Tokez= string:tokens(T, ":"),
|
||||
parse_abs_time_2(Tokez).
|
||||
|
||||
|
||||
|
||||
convert_format(Format) ->
|
||||
convert_format(Format, string:str(Format, "%s")).
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
parse_on_sign($>) -> {ok, geq};
|
||||
parse_on_sign($<) -> {ok, leq}.
|
||||
|
||||
|
||||
|
||||
|
||||
parse_time_rev([F|RTime]) when F =:= $s; F =:= $w; F =:= $u ->
|
||||
Time=lists:reverse(RTime),
|
||||
#tztime{time=parse_abs_time(Time), flag=list_to_atom([F])};
|
||||
parse_time_rev(X=[F|_]) when F-48 < 0; F-48 > 9 ->
|
||||
erlang:error(badtime, X);
|
||||
parse_time_rev(RTime) ->
|
||||
Time=lists:reverse(RTime),
|
||||
#tztime{time=parse_abs_time(Time)}.
|
||||
|
||||
|
||||
|
||||
|
||||
parse_abs_time_2([HS]) ->
|
||||
H= list_to_integer(HS),
|
||||
{H,0,0};
|
||||
parse_abs_time_2([HS,MS]) ->
|
||||
H= list_to_integer(HS),
|
||||
M= list_to_integer(MS),
|
||||
{H,M,0};
|
||||
parse_abs_time_2([HS,MS,SS]) ->
|
||||
H= list_to_integer(HS),
|
||||
M= list_to_integer(MS),
|
||||
S= list_to_integer(SS),
|
||||
{H,M,S};
|
||||
parse_abs_time_2(X) ->
|
||||
erlang:error(badtime, X).
|
||||
|
||||
|
||||
|
||||
parse_save_rev(X=[F|_]) when F-48 < 0; F-48 > 9 ->
|
||||
erlang:error(badsave, lists:reverse(X));
|
||||
parse_save_rev(X) ->
|
||||
parse_time(lists:reverse(X)).
|
||||
|
||||
|
||||
|
||||
convert_format(Format, 0) ->
|
||||
Format;
|
||||
convert_format(Format, Pos) ->
|
||||
First=string:substr(Format, 1, Pos-1),
|
||||
Last=string:substr(Format, Pos+2),
|
||||
string:concat(First, [$~, $s|Last]).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,22 +2,40 @@
|
||||
-include("include/ezic.hrl").
|
||||
|
||||
|
||||
-export([parse/1]).
|
||||
-export([next_event/4]).
|
||||
|
||||
|
||||
|
||||
parse([Name,FromS,ToS,_Type,InS,OnS,AtS,SaveS,Letters]) ->
|
||||
From= ezic_parse:year(FromS),
|
||||
To= ezic_parse:year(ToS),
|
||||
|
||||
% @todo handle year types
|
||||
|
||||
In= ezic_date:month_to_num(InS),
|
||||
On= ezic_parse:day_pattern(OnS),
|
||||
At= ezic_parse:time(AtS),
|
||||
|
||||
Save= ezic_parse:time_val(SaveS),
|
||||
|
||||
Rule= #rule{name=Name, from=From, to=To, type=not_done,
|
||||
in=In, on=On, at=At, save=Save, letters=Letters},
|
||||
{ok, Rule}.
|
||||
|
||||
|
||||
|
||||
% determines the next zone or dst change event
|
||||
% returns the latest possible times the previous period is in effect (`Until -1sec` in most cases)
|
||||
% Rules are sorted
|
||||
next_event(BaseFlat, ZoneEnd, Offset, []) ->
|
||||
next_event(_BaseFlat, ZoneEnd, Offset, []) ->
|
||||
{end_until, make_times(ZoneEnd, Offset)};
|
||||
|
||||
% BaseFlat has offset defined
|
||||
% @todo ensure offset defined on BaseFlat
|
||||
% Rules are sorted in ascending order (oldest first)
|
||||
next_event(BaseFlat=#flatzone{utc_from=#tztime{time={{Year,_,_},_}}},
|
||||
ZoneEnd, ZoneOffset, [Rule|RestRules]) ->
|
||||
next_event(_BaseFlat=#flatzone{utc_from=#tztime{time={{_Year,_,_},_}}},
|
||||
_ZoneEnd, _ZoneOffset, [_Rule|_RestRules]) ->
|
||||
|
||||
not_done.
|
||||
|
||||
@@ -38,3 +56,11 @@ make_times(Until, Offset, DSTOffset) ->
|
||||
|
||||
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
% INTERNAL
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
-export([
|
||||
current/1
|
||||
parse/1
|
||||
, current/1
|
||||
, current_as_of_utc/2
|
||||
, split_by_name/2
|
||||
, sort_ascending/2
|
||||
@@ -14,6 +15,26 @@
|
||||
|
||||
|
||||
|
||||
parse([Name,GmtOffS,Rule,FormatS | UntilTokens]) ->
|
||||
% ?debugVal(GmtOffS),
|
||||
GmtOff= ezic_parse:time_val(GmtOffS),
|
||||
Until = ezic_parse:until(UntilTokens),
|
||||
Format= ezic_parse:tz_abbr(FormatS),
|
||||
|
||||
{ok, #zone{
|
||||
name=Name, gmtoff=GmtOff, rule=Rule,
|
||||
format=Format, until=Until
|
||||
}}.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
current(TzName) ->
|
||||
current_as_of_utc(erlang:universaltime(), TzName).
|
||||
|
||||
@@ -21,10 +42,6 @@ current_as_of_utc(UTCDatetime, TzName) ->
|
||||
Zones= ezic_db:zones(TzName),
|
||||
get_zone_utc(UTCDatetime, Zones).
|
||||
|
||||
%%current_as_of_local(_Datetime, _TzName) ->
|
||||
%% not_done.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +75,7 @@ split_by_name(#zone{name=N}, Zones) ->
|
||||
|
||||
|
||||
sort_descending(#zone{until=U1}, #zone{until=U2}) ->
|
||||
ezic_date:compare_datetimes(U2, U1).
|
||||
ezic_date:compare(U2, U1).
|
||||
|
||||
sort_ascending(Z1=#zone{}, Z2=#zone{}) ->
|
||||
not sort_descending(Z1, Z2).
|
||||
@@ -67,9 +84,16 @@ sort_ascending(Z1=#zone{}, Z2=#zone{}) ->
|
||||
|
||||
% @bug doesn't normalize times. Times are self-relative (to standard time), and Now may come from any timezone unless we're careful about that.
|
||||
%% older_zone(#zone{until=Until}, UTCDatetime) ->
|
||||
%% ezic_date:compare_datetimes(Until, UTCDatetime).
|
||||
%% ezic_date:compare(Until, UTCDatetime).
|
||||
|
||||
|
||||
|
||||
offset_sec(Zone) ->
|
||||
calendar:time_to_seconds((Zone#zone.gmtoff)#tztime.time).
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,42 +2,32 @@
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
prevnext_day_test_() ->
|
||||
|
||||
for_rule_test_() ->
|
||||
[
|
||||
?_assertEqual({2010,11,3}, ezic_date:previous_day("Wed", {2010, 11, 5}))
|
||||
, ?_assertEqual({2010,11,10}, ezic_date:next_day("Wed", {2010, 11, 5}))
|
||||
% last days of months
|
||||
?_assertEqual({2010, 03, 28}, ezic_date:for_rule(#rule{in=3, on={last, "Sun"}}, 2010))
|
||||
, ?_assertEqual({2010, 11, 30}, ezic_date:for_rule(#rule{in=11, on={last, "Tue"}}, 2010))
|
||||
, ?_assertEqual({2010, 11, 24}, ezic_date:for_rule(#rule{in=11, on={last, "Wed"}}, 2010))
|
||||
|
||||
, ?_assertEqual({2010,11,5}, ezic_date:previous_day("Fri", {2010, 11, 5}))
|
||||
, ?_assertEqual({2010,11,5}, ezic_date:next_day("Fri", {2010, 11, 5}))
|
||||
% days =< or >= absolute dates in given month
|
||||
, ?_assertEqual({2010, 11, 14}, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={geq, 9}}}, 2010))
|
||||
, ?_assertEqual({2010, 11, 7}, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={leq, 9}}}, 2010))
|
||||
|
||||
, ?_assertEqual({2010,11,5}, ezic_date:previous_day("Fri", {2010, 11, 10}))
|
||||
, ?_assertEqual({2010,11,12}, ezic_date:next_day("Fri", {2010, 11, 10}))
|
||||
|
||||
, ?_assertError(no_previous_day, ezic_date:previous_day("Wed", {2010, 11, 2}))
|
||||
, ?_assertError(no_next_day, ezic_date:next_day("Wed", {2010, 11, 25}))
|
||||
].
|
||||
|
||||
firstlast_day_of_test_() ->
|
||||
[
|
||||
?_assertEqual({2010,11,24}, ezic_date:last_day_of("Wed", 2010, 11))
|
||||
, ?_assertEqual({2010,11,30}, ezic_date:last_day_of("Tue", 2010, 11))
|
||||
|
||||
, ?_assertEqual({2010,11,14}, ezic_date:first_day_limited("Sun", {geq, 8}, 2010, 11))
|
||||
, ?_assertEqual({2010,11,21}, ezic_date:first_day_limited("Sun", {leq, 25}, 2010, 11))
|
||||
% these should fail
|
||||
, ?_assertError(no_previous_day, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={leq, 1}}}, 2010))
|
||||
, ?_assertError(no_next_day, ezic_date:for_rule(#rule{in=11, on=#tzon{day="Sun", filter={geq, 29}}}, 2010))
|
||||
].
|
||||
|
||||
|
||||
compare_datetimes_test_() ->
|
||||
add_seconds_test_() ->
|
||||
[
|
||||
?_assertNot(ezic_date:compare_datetimes(
|
||||
{{1997,3,{last, "Sun"}},{tztime,{1,0,0},u}}
|
||||
, {1997,1,1} ))
|
||||
?_assertEqual({{2010,11,7},{9,38,01}}, ezic_date:add_seconds({{2010,11,7},{9,38,00}}, 1))
|
||||
, ?_assertEqual({{2010,11,7},{9,38,00}}, ezic_date:add_seconds({{2010,11,7},{9,37,59}}, 1))
|
||||
|
||||
, ?_assertEqual({{2010,11,7},{9,37,59}}, ezic_date:add_seconds({{2010,11,7},{9,38,00}}, -1))
|
||||
, ?_assertError(baddate, ezic_date:add_seconds({{2010,11,nope},{9,38,00}}, -1))
|
||||
, ?_assertError(baddate, ezic_date:add_seconds({2010,11,nope}, -1))
|
||||
].
|
||||
|
||||
|
||||
overlap_test_() ->
|
||||
[
|
||||
?_assert(ezic_date:overlap({1978,only},{{{1977,1,1},#tztime{}}, {{1978,1,1},#tztime{}}}))
|
||||
, ?_assert(ezic_date:overlap({1978,only},{{{1971,1,1},#tztime{}}, {{1978,1,1},#tztime{}}}))
|
||||
, ?_assertNot(ezic_date:overlap({1978,only},{{{1971,1,1},#tztime{}}, {{1977,12,31},#tztime{}}}))
|
||||
].
|
||||
|
||||
76
test/ezic_parse_tests.erl
Normal file
76
test/ezic_parse_tests.erl
Normal file
@@ -0,0 +1,76 @@
|
||||
-module(ezic_parse_tests).
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
year_test_() ->
|
||||
[
|
||||
?_assertEqual(minimum, ezic_parse:year("minimum"))
|
||||
, ?_assertEqual(maximum, ezic_parse:year("maximum"))
|
||||
, ?_assertEqual(only, ezic_parse:year("only"))
|
||||
, ?_assertEqual(1978, ezic_parse:year("1978"))
|
||||
, ?_assertError(badarg, ezic_parse:year("asdf"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
time_test_() ->
|
||||
[
|
||||
?_assertEqual(#tztime{time={0,0,0}}, ezic_parse:time("-"))
|
||||
, ?_assertEqual(#tztime{time={2,0,0}}, ezic_parse:time("2:00"))
|
||||
, ?_assertEqual(#tztime{time={15,0,0}}, ezic_parse:time("15:00"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}}, ezic_parse:time("1:28:14"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_parse:time("1:28:14w"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_parse:time("1:28:14s"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14u"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14g"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_parse:time("1:28:14z"))
|
||||
|
||||
, ?_assertError(badtime, ezic_parse:time("1:28:14wtf?"))
|
||||
, ?_assertError(badtime, ezic_parse:time("1:28:14:00"))
|
||||
].
|
||||
|
||||
|
||||
time_val_test_() ->
|
||||
[
|
||||
?_assertEqual({0,0,0}, ezic_parse:time_val("-"))
|
||||
, ?_assertEqual({2,0,0}, ezic_parse:time_val("2:00"))
|
||||
, ?_assertEqual({15,0,0}, ezic_parse:time_val("15:00"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14w"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14s"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14u"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14g"))
|
||||
, ?_assertEqual({1,28,14}, ezic_parse:time_val("1:28:14z"))
|
||||
|
||||
, ?_assertError(badtime, ezic_parse:time_val("1:28:14wtf?"))
|
||||
, ?_assertError(badtime, ezic_parse:time_val("1:28:14:00"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
day_pattern_test_() ->
|
||||
[
|
||||
?_assertEqual(5, ezic_parse:day_pattern("5"))
|
||||
|
||||
, ?_assertEqual({last, "Sun"}, ezic_parse:day_pattern("lastSun"))
|
||||
, ?_assertEqual({last, "Mon"}, ezic_parse:day_pattern("lastMon"))
|
||||
, ?_assertError(badday, ezic_parse:day_pattern("lastFoo"))
|
||||
|
||||
, ?_assertEqual(#tzon{day="Sun", filter={geq, 8}}, ezic_parse:day_pattern("Sun>=8"))
|
||||
, ?_assertEqual(#tzon{day="Sun", filter={leq, 25}}, ezic_parse:day_pattern("Sun<=25"))
|
||||
, ?_assertError(badday, ezic_parse:day_pattern("Foo<=25"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
|
||||
tz_abbr_test_() ->
|
||||
[
|
||||
?_assertEqual("POS", ezic_parse:tz_abbr("POS"))
|
||||
, ?_assertEqual("P~sS", ezic_parse:tz_abbr("P%sS"))
|
||||
, ?_assertEqual("PS~s", ezic_parse:tz_abbr("PS%s"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
@@ -2,89 +2,3 @@
|
||||
-include("include/ezic.hrl").
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
|
||||
parse_fromto_test_() ->
|
||||
[
|
||||
?_assertEqual(minimum, ezic_record:parse_from("minimum"))
|
||||
, ?_assertEqual(minimum, ezic_record:parse_to("minimum"))
|
||||
|
||||
, ?_assertEqual(maximum, ezic_record:parse_from("maximum"))
|
||||
, ?_assertEqual(maximum, ezic_record:parse_to("maximum"))
|
||||
|
||||
, ?_assertError(badarg, ezic_record:parse_from("only"))
|
||||
, ?_assertEqual(only, ezic_record:parse_to("only"))
|
||||
|
||||
, ?_assertEqual(1978, ezic_record:parse_from("1978"))
|
||||
, ?_assertEqual(1978, ezic_record:parse_to("1978"))
|
||||
|
||||
, ?_assertError(badarg, ezic_record:parse_from("asdf"))
|
||||
, ?_assertError(badarg, ezic_record:parse_to("asdf"))
|
||||
].
|
||||
|
||||
|
||||
parse_time_test_() ->
|
||||
[
|
||||
?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_time("-"))
|
||||
, ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_time("2:00"))
|
||||
, ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_time("15:00"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_time("1:28:14"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_record:parse_time("1:28:14u"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_record:parse_time("1:28:14w"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_record:parse_time("1:28:14s"))
|
||||
|
||||
, ?_assertError(badtime, ezic_record:parse_time("1:28:14wtf?"))
|
||||
, ?_assertError(badtime, ezic_record:parse_time("1:28:14:00"))
|
||||
].
|
||||
|
||||
|
||||
parse_at_test_() ->
|
||||
[
|
||||
?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_at("-"))
|
||||
, ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_at("2:00"))
|
||||
, ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_at("15:00"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_at("1:28:14"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=u}, ezic_record:parse_at("1:28:14u"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=w}, ezic_record:parse_at("1:28:14w"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}, flag=s}, ezic_record:parse_at("1:28:14s"))
|
||||
, ?_assertError(badtime, ezic_record:parse_at("1:28:14wtf?"))
|
||||
].
|
||||
|
||||
|
||||
parse_save_test_() ->
|
||||
[
|
||||
?_assertEqual(#tztime{time={0,0,0}}, ezic_record:parse_save("-"))
|
||||
, ?_assertEqual(#tztime{time={2,0,0}}, ezic_record:parse_save("2:00"))
|
||||
, ?_assertEqual(#tztime{time={15,0,0}}, ezic_record:parse_save("15:00"))
|
||||
, ?_assertEqual(#tztime{time={1,28,14}}, ezic_record:parse_save("1:28:14"))
|
||||
, ?_assertError(badsave, ezic_record:parse_save("1:28:14u"))
|
||||
, ?_assertError(badsave, ezic_record:parse_save("1:28:14w"))
|
||||
, ?_assertError(badsave, ezic_record:parse_save("1:28:14s"))
|
||||
, ?_assertError(badsave, ezic_record:parse_save("1:28:14wtf?"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
parse_on_test_() ->
|
||||
[
|
||||
?_assertEqual(5, ezic_record:parse_on("5"))
|
||||
|
||||
, ?_assertEqual({last, "Sun"}, ezic_record:parse_on("lastSun"))
|
||||
, ?_assertEqual({last, "Mon"}, ezic_record:parse_on("lastMon"))
|
||||
, ?_assertError(badday, ezic_record:parse_on("lastFoo"))
|
||||
|
||||
, ?_assertEqual(#tzon{day="Sun", filter={geq, 8}}, ezic_record:parse_on("Sun>=8"))
|
||||
, ?_assertEqual(#tzon{day="Sun", filter={leq, 25}}, ezic_record:parse_on("Sun<=25"))
|
||||
, ?_assertError(badday, ezic_record:parse_on("Foo<=25"))
|
||||
].
|
||||
|
||||
|
||||
convert_format_test_() ->
|
||||
[
|
||||
?_assertEqual("POS", ezic_record:convert_format("POS"))
|
||||
, ?_assertEqual("P~sS", ezic_record:convert_format("P%sS"))
|
||||
].
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
all() ->
|
||||
eunit:test(ezic_record),
|
||||
eunit:test(ezic_date),
|
||||
eunit:test(ezic_zone).
|
||||
eunit:test(ezic_record)
|
||||
, eunit:test(ezic_date)
|
||||
, eunit:test(ezic_zone)
|
||||
, eunit:test(ezic_parse)
|
||||
|
||||
,ok.
|
||||
|
||||
Reference in New Issue
Block a user