mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-18 22:33:33 +00:00
Code review and use isodate library to handle durations for robustly
This commit is contained in:
@@ -184,6 +184,13 @@ endif
|
|||||||
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
|
cp -r dist/working/python-dateutil-2.8.1/dateutil dist/blenderbim/libs/site/packages/
|
||||||
rm -rf dist/working
|
rm -rf dist/working
|
||||||
|
|
||||||
|
# Provides duration parsing for construction sequencing
|
||||||
|
mkdir dist/working
|
||||||
|
cd dist/working && wget https://files.pythonhosted.org/packages/b1/80/fb8c13a4cd38eb5021dc3741a9e588e4d1de88d895c1910c6fc8a08b7a70/isodate-0.6.0.tar.gz
|
||||||
|
cd dist/working && tar -xzvf isodate*
|
||||||
|
cp -r dist/working/isodate-0.6.0/src/isodate dist/blenderbim/libs/site/packages/
|
||||||
|
rm -rf dist/working
|
||||||
|
|
||||||
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
# Provides jsgantt-improved supports for web-based construction sequencing gantt charts
|
||||||
mkdir dist/working
|
mkdir dist/working
|
||||||
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
cd dist/working && wget https://raw.githubusercontent.com/jsGanttImproved/jsgantt-improved/master/dist/jsgantt.js
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import os
|
|||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
import isodate
|
||||||
import pystache
|
import pystache
|
||||||
import webbrowser
|
import webbrowser
|
||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
@@ -302,7 +303,7 @@ class LoadTaskProperties(bpy.types.Operator):
|
|||||||
task_time = Data.task_times[task["TaskTime"]]
|
task_time = Data.task_times[task["TaskTime"]]
|
||||||
item.start = self.canonicalise_time(task_time["ScheduleStart"])
|
item.start = self.canonicalise_time(task_time["ScheduleStart"])
|
||||||
item.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
item.finish = self.canonicalise_time(task_time["ScheduleFinish"])
|
||||||
item.duration = str(task_time["ScheduleDuration"].days) if task_time["ScheduleDuration"] else "-"
|
item.duration = isodate.duration_isoformat(task_time["ScheduleDuration"]) if task_time["ScheduleDuration"] else "-"
|
||||||
else:
|
else:
|
||||||
item.start = "-"
|
item.start = "-"
|
||||||
item.finish = "-"
|
item.finish = "-"
|
||||||
@@ -431,7 +432,7 @@ class EnableEditingTaskTime(bpy.types.Operator):
|
|||||||
if data_type == "string":
|
if data_type == "string":
|
||||||
if isinstance(data[attribute.name()], datetime):
|
if isinstance(data[attribute.name()], datetime):
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
new.string_value = "" if new.is_null else data[attribute.name()].isoformat()
|
||||||
elif isinstance(data[attribute.name()], timedelta):
|
elif isinstance(data[attribute.name()], isodate.Duration):
|
||||||
new.string_value = "" if new.is_null else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
new.string_value = "" if new.is_null else ifcopenshell.util.date.datetime2ifc(data[attribute.name()], "IfcDuration")
|
||||||
else:
|
else:
|
||||||
new.string_value = "" if new.is_null else data[attribute.name()]
|
new.string_value = "" if new.is_null else data[attribute.name()]
|
||||||
@@ -500,7 +501,7 @@ class EditTaskTime(bpy.types.Operator):
|
|||||||
except:
|
except:
|
||||||
attributes[key] = None
|
attributes[key] = None
|
||||||
elif key == "ScheduleDuration":
|
elif key == "ScheduleDuration":
|
||||||
attributes[key] = ifcopenshell.util.date.ifc2datetime(value)
|
attributes[key] = isodate.parse_duration(value)
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +1,28 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from re import findall
|
from re import findall
|
||||||
|
|
||||||
# https://gist.github.com/spatialtime/c1924a3b178b4fe721fe406e0bf1a1dc
|
try:
|
||||||
import re
|
import isodate
|
||||||
from datetime import timedelta
|
except:
|
||||||
|
pass # Duration parsing not supported
|
||||||
|
|
||||||
def format_duration(td):
|
|
||||||
s = td.seconds
|
|
||||||
ms = td.microseconds
|
|
||||||
if ms != 0: # Round microseconds to milliseconds.
|
|
||||||
ms /= 1000000
|
|
||||||
ms = round(ms,3)
|
|
||||||
s += ms
|
|
||||||
return "P{}DT{}S".format(td.days,s)
|
|
||||||
|
|
||||||
def parse_duration(iso_duration):
|
|
||||||
m = re.match(r'^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:.\d+)?)S)?$',
|
|
||||||
iso_duration)
|
|
||||||
if m is None:
|
|
||||||
raise ValueError("invalid ISO 8601 duration string")
|
|
||||||
days = 0
|
|
||||||
hours = 0
|
|
||||||
minutes = 0
|
|
||||||
seconds = 0.0
|
|
||||||
if m[3]:
|
|
||||||
days = int(m[3])
|
|
||||||
if m[4]:
|
|
||||||
hours = int(m[4])
|
|
||||||
if m[5]:
|
|
||||||
minutes = int(m[5])
|
|
||||||
if m[6]:
|
|
||||||
seconds = float(m[6])
|
|
||||||
return timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
|
|
||||||
|
|
||||||
|
|
||||||
def duration2dict(duration):
|
|
||||||
results = {}
|
|
||||||
for number, unit in findall("(?P<number>\d+)(?P<period>S|M|H|D|W|Y)", duration):
|
|
||||||
results[unit] = number
|
|
||||||
return results
|
|
||||||
|
|
||||||
|
|
||||||
def ifc2datetime(element):
|
def ifc2datetime(element):
|
||||||
if isinstance(element, str) and element[0] == "P": # IfcDuration
|
if isinstance(element, str) and element[0] == "P": # IfcDuration
|
||||||
return parse_duration(element)
|
duration = isodate.parse_duration(element)
|
||||||
|
if isinstance(duration, datetime.timedelta):
|
||||||
|
components = {
|
||||||
|
"days": getattr(duration, "days", 0),
|
||||||
|
"hours": 0,
|
||||||
|
"minutes": 0,
|
||||||
|
"seconds": getattr(duration, "seconds", 0),
|
||||||
|
}
|
||||||
|
if components["seconds"]:
|
||||||
|
components["hours"], components["minutes"], components["seconds"] = [
|
||||||
|
int(i) for i in str(datetime.timedelta(seconds=components["seconds"])).split(":")
|
||||||
|
]
|
||||||
|
duration = isodate.Duration(**components)
|
||||||
|
return duration
|
||||||
elif isinstance(element, str) and element[2] == ":": # IfcTime
|
elif isinstance(element, str) and element[2] == ":": # IfcTime
|
||||||
return datetime.time.fromisoformat(element)
|
return datetime.time.fromisoformat(element)
|
||||||
elif isinstance(element, str) and ":" in element: # IfcDateTime
|
elif isinstance(element, str) and ":" in element: # IfcDateTime
|
||||||
@@ -72,11 +50,14 @@ def ifc2datetime(element):
|
|||||||
|
|
||||||
|
|
||||||
def datetime2ifc(dt, ifc_type):
|
def datetime2ifc(dt, ifc_type):
|
||||||
if isinstance(dt, str) and ifc_type != "IfcDuration":
|
if isinstance(dt, str):
|
||||||
|
if ifc_type == "IfcDuration":
|
||||||
|
return dt
|
||||||
dt = datetime.datetime.fromisoformat(dt)
|
dt = datetime.datetime.fromisoformat(dt)
|
||||||
|
|
||||||
if ifc_type == "IfcDuration":
|
if ifc_type == "IfcDuration":
|
||||||
return format_duration(dt)
|
return isodate.duration_isoformat(dt)
|
||||||
if ifc_type == "IfcTimeStamp":
|
elif ifc_type == "IfcTimeStamp":
|
||||||
return int(dt.timestamp())
|
return int(dt.timestamp())
|
||||||
elif ifc_type == "IfcDateTime":
|
elif ifc_type == "IfcDateTime":
|
||||||
if isinstance(dt, datetime.datetime):
|
if isinstance(dt, datetime.datetime):
|
||||||
|
|||||||
Reference in New Issue
Block a user