From 4e920a40a11062c88d2bdcbc73f4d8cec2e58cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Wed, 4 Oct 2023 09:31:59 +0200 Subject: [PATCH 01/22] Modify python versions on github actions (#476) --- .github/workflows/test_cornflow_client.yml | 4 ++-- .github/workflows/test_cornflow_dags.yml | 2 +- .github/workflows/test_cornflow_server.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test_cornflow_client.yml b/.github/workflows/test_cornflow_client.yml index 22953acae..bf56d3606 100644 --- a/.github/workflows/test_cornflow_client.yml +++ b/.github/workflows/test_cornflow_client.yml @@ -27,7 +27,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [3.8, 3.9] + python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] os: [ubuntu-latest, macOS-latest, windows-latest] steps: @@ -57,7 +57,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [ 3.8, 3.9 ] + python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] os: [ ubuntu-latest ] steps: diff --git a/.github/workflows/test_cornflow_dags.yml b/.github/workflows/test_cornflow_dags.yml index a7839e42c..5a36f8ace 100644 --- a/.github/workflows/test_cornflow_dags.yml +++ b/.github/workflows/test_cornflow_dags.yml @@ -25,7 +25,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [3.7, 3.8] + python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] os: [ubuntu-latest] steps: diff --git a/.github/workflows/test_cornflow_server.yml b/.github/workflows/test_cornflow_server.yml index 7eabff50c..4d7ec6d2c 100644 --- a/.github/workflows/test_cornflow_server.yml +++ b/.github/workflows/test_cornflow_server.yml @@ -27,7 +27,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [3.8] + python-version: [3.8, 3.9, '3.10', '3.11'] os: [ubuntu-latest] services: From 00e55828f93c56dd1693a8641d35ddeea1a17330 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Wed, 4 Oct 2023 15:58:56 +0200 Subject: [PATCH 02/22] Feature/airflow version (#478) * Upgraded Dockerfiles to Python 3.10 Upgraded airflow to 2.7.1 Run workflows on workflow change just in case * Updated requirements.txt * Now workflows get properly run * Drop 3.7 support * Drop support for acopy solver of tsp as has dependency conflicts with Airflow * Fixed unit test of dags that still referenced acopy --- .github/workflows/test_cornflow_client.yml | 3 ++- .github/workflows/test_cornflow_dags.yml | 5 +++-- .github/workflows/test_cornflow_server.yml | 3 ++- cornflow-dags/DAG/tsp/__init__.py | 4 ++-- cornflow-dags/DAG/tsp/schemas/config.json | 2 +- cornflow-dags/DAG/tsp/solvers/ACOpy.py | 18 ----------------- cornflow-dags/DAG/tsp/solvers/__init__.py | 1 - cornflow-dags/requirements-dev.txt | 5 ++--- cornflow-dags/requirements.txt | 23 ++++++++++------------ cornflow-dags/tests/test_dags.py | 3 --- cornflow-server/Dockerfile | 2 +- cornflow-server/airflow_config/Dockerfile | 10 +++++----- cornflow-server/requirements.txt | 3 ++- 13 files changed, 30 insertions(+), 52 deletions(-) delete mode 100644 cornflow-dags/DAG/tsp/solvers/ACOpy.py diff --git a/.github/workflows/test_cornflow_client.yml b/.github/workflows/test_cornflow_client.yml index 4b04692dd..799494992 100644 --- a/.github/workflows/test_cornflow_client.yml +++ b/.github/workflows/test_cornflow_client.yml @@ -5,6 +5,7 @@ on: types: [ opened, edited, synchronize, reopened ] paths: - 'libs/client/**' + - '.github/workflows/test_cornflow_client.yml' - '!libs/client/README.rst' - '!libs/client/setup.py' push: @@ -84,7 +85,7 @@ jobs: cd cornflow-server python -m venv afvenv source afvenv/bin/activate - AIRFLOW_VERSION=2.2.1 + AIRFLOW_VERSION=2.7.1 PYTHON_VERSION="$(python3 --version | cut -d " " -f 2 | cut -d "." -f 1-2)" CLIENT_BRANCH="${{ github.head_ref || github.ref_name }}" CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt" diff --git a/.github/workflows/test_cornflow_dags.yml b/.github/workflows/test_cornflow_dags.yml index 5a36f8ace..e36981ffa 100644 --- a/.github/workflows/test_cornflow_dags.yml +++ b/.github/workflows/test_cornflow_dags.yml @@ -5,6 +5,7 @@ on: types: [ opened, edited, synchronize, reopened ] paths: - 'cornflow-dags/**' + - '.github/workflows/test_cornflow_dags.yml' - '!cornflow-dags/README.rst' push: branches: @@ -25,7 +26,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [3.7, 3.8, 3.9, '3.10', '3.11'] + python-version: [3.8, 3.9, '3.10', '3.11'] os: [ubuntu-latest] steps: @@ -46,7 +47,7 @@ jobs: python -m pip install -U "git+https://github.com/baobabsoluciones/cornflow@${CLIENT_BRANCH}#subdirectory=libs/client" - name: Install airflow run: | - AIRFLOW_VERSION=2.1.0 + AIRFLOW_VERSION=2.7.1 PYTHON_VERSION="$(python3 --version | cut -d " " -f 2 | cut -d "." -f 1-2)" CLIENT_BRANCH="${{ github.head_ref || github.ref_name }}" CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt" diff --git a/.github/workflows/test_cornflow_server.yml b/.github/workflows/test_cornflow_server.yml index 4d7ec6d2c..18634e058 100644 --- a/.github/workflows/test_cornflow_server.yml +++ b/.github/workflows/test_cornflow_server.yml @@ -5,6 +5,7 @@ on: types: [ opened, edited, synchronize, reopened ] paths: - 'cornflow-server/**' + - '.github/workflows/test_cornflow_server.yml' - '!cornflow-server/docs/**' - '!cornflow-server/README.rst' push: @@ -71,7 +72,7 @@ jobs: run: | python -m venv afvenv source afvenv/bin/activate - AIRFLOW_VERSION=2.2.1 + AIRFLOW_VERSION=2.7.1 PYTHON_VERSION="$(python3 --version | cut -d " " -f 2 | cut -d "." -f 1-2)" CLIENT_BRANCH="${{ github.head_ref || github.ref_name }}" CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt" diff --git a/cornflow-dags/DAG/tsp/__init__.py b/cornflow-dags/DAG/tsp/__init__.py index de3723557..eaad6ee0a 100644 --- a/cornflow-dags/DAG/tsp/__init__.py +++ b/cornflow-dags/DAG/tsp/__init__.py @@ -5,7 +5,7 @@ from typing import List, Dict import os -from .solvers import TSPNaive, ACOpy, OrToolsCP +from .solvers import TSPNaive, OrToolsCP from .core import Instance, Solution @@ -13,7 +13,7 @@ class TspApp(ApplicationCore): name = "tsp" instance = Instance solution = Solution - solvers = dict(naive=TSPNaive, aco=ACOpy, cpsat=OrToolsCP) + solvers = dict(naive=TSPNaive, cpsat=OrToolsCP) schema = load_json(os.path.join(os.path.dirname(__file__), "schemas/config.json")) @property diff --git a/cornflow-dags/DAG/tsp/schemas/config.json b/cornflow-dags/DAG/tsp/schemas/config.json index 3df23efe3..a62dcb567 100644 --- a/cornflow-dags/DAG/tsp/schemas/config.json +++ b/cornflow-dags/DAG/tsp/schemas/config.json @@ -8,7 +8,7 @@ "gap": {"type": "number"}, "solver": { "type": "string", - "enum": ["naive", "aco", "cpsat"], + "enum": ["naive", "cpsat"], "default": "naive" } } diff --git a/cornflow-dags/DAG/tsp/solvers/ACOpy.py b/cornflow-dags/DAG/tsp/solvers/ACOpy.py deleted file mode 100644 index 456d3c982..000000000 --- a/cornflow-dags/DAG/tsp/solvers/ACOpy.py +++ /dev/null @@ -1,18 +0,0 @@ -from ..core import Experiment, Solution -from pytups import TupList -import acopy as aco -from cornflow_client.constants import SOLUTION_STATUS_FEASIBLE, STATUS_UNDEFINED - - -class ACOpy(Experiment): - def solve(self, options: dict): - solver = aco.Solver(rho=options.get("rho", 0.03), q=options.get("q", 1)) - timeLimit_plugin = aco.plugins.TimeLimit(options.get("timeLimit", 10)) - solver.add_plugin(timeLimit_plugin) - colony = aco.Colony(alpha=options.get("alpha", 1), beta=options.get("beta", 3)) - problem = self.instance.to_tsplib95() - G = problem.get_graph() - tour = solver.solve(G, colony, limit=100) - solution = TupList(dict(pos=pos, node=el) for pos, el in enumerate(tour.nodes)) - self.solution = Solution(dict(route=solution)) - return dict(status_sol=SOLUTION_STATUS_FEASIBLE, status=STATUS_UNDEFINED) diff --git a/cornflow-dags/DAG/tsp/solvers/__init__.py b/cornflow-dags/DAG/tsp/solvers/__init__.py index bf5a4df5f..4e05d4b71 100644 --- a/cornflow-dags/DAG/tsp/solvers/__init__.py +++ b/cornflow-dags/DAG/tsp/solvers/__init__.py @@ -1,3 +1,2 @@ -from .ACOpy import ACOpy from .naive import TSPNaive from .cp_model import OrToolsCP diff --git a/cornflow-dags/requirements-dev.txt b/cornflow-dags/requirements-dev.txt index b66996219..54d6b0ac7 100644 --- a/cornflow-dags/requirements-dev.txt +++ b/cornflow-dags/requirements-dev.txt @@ -1,5 +1,4 @@ -r requirements.txt -apache-airflow>=2.0.1 coverage -numpyencoder==0.3.0 -openpyxl==3.0.9 +numpyencoder +matplotlib diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 9dc65e018..613a12cfb 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,14 +1,11 @@ -cornflow-client -orloge>=0.13 -PuLP>=2.3 -pandas>=1.0 +cornflow-client<=1.0.15 +orloge<=0.17.2 +PuLP<=2.7 +pandas<=2.1.1 hackathonbaobab2020[solvers] @ git+https://github.com/baobabsoluciones/hackathonbaobab2020@main -marshmallow -pytups -ortools -xmltodict -openpyxl -pyomo -acopy -tsplib95 -matplotlib \ No newline at end of file +pytups<=0.86.2 +ortools<=9.7.2996 +xmltodict<=0.13.0 +openpyxl<=3.1.2 +pyomo<=6.6.2 +tsplib95<=0.7.1 \ No newline at end of file diff --git a/cornflow-dags/tests/test_dags.py b/cornflow-dags/tests/test_dags.py index 96c2d2ee9..57dedced2 100644 --- a/cornflow-dags/tests/test_dags.py +++ b/cornflow-dags/tests/test_dags.py @@ -162,9 +162,6 @@ def setUp(self): self.app = TspApp() - def test_solve_aco(self): - return self.test_try_solving_testcase(dict(solver="aco", **self.config)) - def test_solve_cpsat(self): return self.test_try_solving_testcase(dict(solver="cpsat", **self.config)) diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index e490fa427..6520f93cb 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -1,7 +1,7 @@ # VERSION 2.0.2 # AUTHOR: sistemas@baobabsoluciones.es -FROM python:3.8-slim-buster +FROM python:3.10-slim-buster LABEL maintainer="sistemas@baobabsoluciones" # Never prompt the user for choices on installation/configuration of packages diff --git a/cornflow-server/airflow_config/Dockerfile b/cornflow-server/airflow_config/Dockerfile index 40aaefb74..632b43a45 100644 --- a/cornflow-server/airflow_config/Dockerfile +++ b/cornflow-server/airflow_config/Dockerfile @@ -1,8 +1,8 @@ -# VERSION 2.x.x +# VERSION 2.7.1 # AUTHOR: sistemas@baobabsoluciones.es -# DESCRIPTION: Airflow 2.x.x image personalized for use with Cornflow (from puckel/docker-airflow https://github.com/puckel/docker-airflow by "Puckel_") +# DESCRIPTION: Airflow 2.7.1 image personalized for use with Cornflow (from puckel/docker-airflow https://github.com/puckel/docker-airflow by "Puckel_") -FROM python:3.8-slim-buster +FROM python:3.10-slim-buster LABEL maintainer="sistemas@baobabsoluciones" # Never prompt the user for choices on installation/configuration of packages @@ -10,9 +10,9 @@ ENV DEBIAN_FRONTEND noninteractive ENV TERM linux # Airflow vars -ARG AIRFLOW_VERSION=2.2.4 +ARG AIRFLOW_VERSION=2.7.1 ARG AIRFLOW_USER_HOME=/usr/local/airflow -ARG CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-3.8.txt" +ARG CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-3.10.txt" ARG AIRFLOW__CORE__LOAD_EXAMPLES=False ENV AIRFLOW_HOME=${AIRFLOW_USER_HOME} diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index ca4395140..e2d6fcefe 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -14,7 +14,8 @@ Flask-Migrate<=4.0.4 Flask-RESTful<=0.3.9 Flask-SQLAlchemy==2.5.1 gevent==23.9.1 -greenlet<=2.0.2 +greenlet<=2.0.2;python_version<"3.11" +greenlet==3.0.0;python_version>="3.11" gunicorn<=20.1.0 jsonpatch<=1.32 ldap3<=2.9.1 From 7f40a93e68959dda4ea936957cba73b79ca7e61a Mon Sep 17 00:00:00 2001 From: marioncottard <86973971+marioncottard@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:04:28 +0200 Subject: [PATCH 03/22] Feature/rostering opening hours (#463) * Changed all hours from int to string * Cleaning * Docstrings * Adjustements for 24/7 store * Cleaning * Updated requirements and workflows * Updated requirements * Changed workflow --------- Co-authored-by: Guillermo Gonzalez-Santander --- .github/workflows/test_cornflow_client.yml | 2 +- .github/workflows/test_cornflow_dags.yml | 4 +- cornflow-dags/DAG/rostering/core/instance.py | 238 +- cornflow-dags/DAG/rostering/core/solution.py | 1 - cornflow-dags/DAG/rostering/core/tools.py | 14 +- .../DAG/rostering/data/test_instance_1.json | 164 +- .../DAG/rostering/data/test_instance_2.json | 152 +- .../DAG/rostering/data/test_instance_3.json | 156 +- .../DAG/rostering/data/test_instance_4.json | 152 +- .../DAG/rostering/data/test_instance_5.json | 152 +- .../DAG/rostering/data/test_instance_6.json | 7680 ++++++++--------- .../DAG/rostering/data/test_instance_7.json | 1314 +-- .../DAG/rostering/data/test_instance_8.json | 1326 +-- .../DAG/rostering/schemas/instance.json | 18 +- .../rostering/schemas/instance_checks.json | 114 +- .../DAG/rostering/solvers/mip_model.py | 10 +- .../core/experiment.py | 21 +- cornflow-dags/requirements.txt | 2 +- 18 files changed, 5917 insertions(+), 5603 deletions(-) diff --git a/.github/workflows/test_cornflow_client.yml b/.github/workflows/test_cornflow_client.yml index 799494992..cdc0cb600 100644 --- a/.github/workflows/test_cornflow_client.yml +++ b/.github/workflows/test_cornflow_client.yml @@ -58,7 +58,7 @@ jobs: strategy: max-parallel: 21 matrix: - python-version: [ 3.8, 3.9, '3.10', '3.11' ] + python-version: [3.8, 3.9, '3.10', '3.11'] os: [ ubuntu-latest ] steps: diff --git a/.github/workflows/test_cornflow_dags.yml b/.github/workflows/test_cornflow_dags.yml index e36981ffa..7f9d83d29 100644 --- a/.github/workflows/test_cornflow_dags.yml +++ b/.github/workflows/test_cornflow_dags.yml @@ -51,8 +51,8 @@ jobs: PYTHON_VERSION="$(python3 --version | cut -d " " -f 2 | cut -d "." -f 1-2)" CLIENT_BRANCH="${{ github.head_ref || github.ref_name }}" CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints-${AIRFLOW_VERSION}/constraints-${PYTHON_VERSION}.txt" - pip install "apache-airflow==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" - python -m pip uninstall cornflow-client -y + python -m pip install "apache-airflow==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" + python -m pip install -U orloge pulp python -m pip install -U "git+https://github.com/baobabsoluciones/cornflow@${CLIENT_BRANCH}#subdirectory=libs/client" airflow db init airflow users create \ diff --git a/cornflow-dags/DAG/rostering/core/instance.py b/cornflow-dags/DAG/rostering/core/instance.py index d64d65fb9..474d176a1 100644 --- a/cornflow-dags/DAG/rostering/core/instance.py +++ b/cornflow-dags/DAG/rostering/core/instance.py @@ -19,6 +19,8 @@ get_date_from_string, get_date_string_from_ts, get_hour_from_date_time, + get_hour_string_from_date_time, + get_hour_string_from_hour_minute, get_one_date, get_time_slot_string, get_week_from_ts, @@ -182,10 +184,6 @@ def to_dict(self) -> Dict: def cache_properties(self): """Caches the list of weeks, dates and time slots and its associated properties""" - # We check if the slot length is coherent - if self._get_slot_length() % 5: - print("WARNING, SLOT LENGTH MUST BE MULTIPLES OF 5") - self.weeks = self._get_weeks() self.opening_days = self._get_opening_days() self.dates = self._get_dates() @@ -194,7 +192,11 @@ def cache_properties(self): self.time_slots_properties = self._get_time_slots_properties() def check(self) -> dict: - return dict(incoherent_foreign_keys=self.check_indexes_coherence()) + return SuperDict( + incoherent_foreign_keys=self.check_indexes_coherence(), + timeslot_length=self.check_timeslot_length(), + **self.check_timeslot_coherence(), + ).vfilter(lambda v: len(v)) def check_indexes_coherence(self) -> list: errors = list() @@ -214,6 +216,80 @@ def check_indexes_coherence(self) -> list: return errors + def check_timeslot_length(self): + slot_length = self._get_slot_length() + if slot_length not in [15, 30, 60]: + return dict(timeslot_length=slot_length) + return dict() + + def check_timeslot_coherence(self): + checks = SuperDict( + weekly_schedule_timeslots=TupList(), + schedule_exceptions_timeslots=TupList(), + shift_hours_timeslots=TupList(), + employee_preferences_timeslots=TupList(), + ) + slot_length = self._get_slot_length() + weekly_schedule = self._get_weekly_schedule(round_ts=False) + schedule_exceptions = self._get_schedule_exceptions(round_ts=False) + contract_start_hours = self._get_employees_contract_starting_hour( + round_ts=False + ) + contract_end_hours = self._get_employees_contract_ending_hour(round_ts=False) + employee_preferences = self._get_employee_preferences() + + for key, values in weekly_schedule.items(): + checks["weekly_schedule_timeslots"] += TupList( + { + "weekday": key, + "hour": get_hour_string_from_hour_minute(hour=v[0], minute=v[1]), + } + for v in values + if v[1] % slot_length != 0 + ) + TupList( + { + "weekday": key, + "hour": get_hour_string_from_hour_minute(hour=v[2], minute=v[3]), + } + for v in values + if v[3] % slot_length != 0 + ) + + for key, values in schedule_exceptions.items(): + checks["schedule_exceptions_timeslots"] += TupList( + { + "date": key, + "hour": get_hour_string_from_hour_minute(hour=v[0], minute=v[1]), + } + for v in values + if v[1] % slot_length != 0 + ) + TupList( + { + "date": key, + "hour": get_hour_string_from_hour_minute(hour=v[2], minute=v[3]), + } + for v in values + if v[3] % slot_length != 0 + ) + + checks["shift_hours_timeslots"] += TupList( + {"week": week, "employee": employee, "hour": hour} + for (week, employee), hour in contract_start_hours.items() + if int(hour[3:]) % slot_length != 0 + ) + TupList( + {"week": week, "employee": employee, "hour": hour} + for (week, employee), hour in contract_end_hours.items() + if int(hour[3:]) % slot_length != 0 + ) + + checks["employee_preferences_timeslots"] += TupList( + {"date": date, "employee": employee, "hour": hour_string} + for (employee, date, _, hour_string) in employee_preferences + if int(hour_string[3:]) % slot_length != 0 + ) + + return checks.vfilter(lambda v: len(v)) + def _get_weeks(self) -> TupList: """ Returns a TupList with the starting date of each week in date time format @@ -281,10 +357,19 @@ def _get_time_slots(self) -> TupList: ts = ( TupList( - key + timedelta(hours=h_start, minutes=self._get_slot_length() * x) + key + + timedelta( + hours=h_start, minutes=m_start + self._get_slot_length() * x + ) for key, value in date_shift.items() - for (h_start, h_end) in value - for x in range(int(self._hour_to_slot(h_end - h_start))) + for (h_start, m_start, h_end, m_end) in value + for x in range( + int( + self._minutes_to_slot( + 60 * h_end + m_end - 60 * h_start - m_start + ) + ) + ) ) .vfilter( # Remove schedule exceptions. @@ -298,10 +383,12 @@ def _get_time_slots(self) -> TupList: ts_schedule_exceptions = TupList( get_date_from_string(d) - + timedelta(hours=h_start, minutes=self._get_slot_length() * x) + + timedelta(hours=h_start, minutes=m_start + self._get_slot_length() * x) for d, value in self._get_schedule_exceptions().items() - for (h_start, h_end) in value - for x in range(int(self._hour_to_slot(h_end - h_start))) + for (h_start, m_start, h_end, m_end) in value + for x in range( + int(self._minutes_to_slot(60 * h_end + m_end - 60 * h_start - m_start)) + ) ) # In case some shift overlap we apply unique ts_total = (ts + ts_schedule_exceptions).unique2().sorted() @@ -321,6 +408,7 @@ def _get_time_slots_properties(self) -> SuperDict: "date": get_date_string_from_ts(ts), "week": get_week_from_ts(ts), "hour": get_hour_from_date_time(ts), + "hour_string": get_hour_string_from_date_time(ts), } for ts in self.time_slots } @@ -342,6 +430,14 @@ def _get_hour_from_ts(self, ts): """Returns the hour of a given time slot""" return self.time_slots_properties[ts]["hour"] + def _get_hour_string_from_ts(self, ts): + """Returns the hour of a given time slot""" + return self.time_slots_properties[ts]["hour_string"] + + def _get_hour_from_hour_string(self, st): + """Returns a float corresponding to the given hour""" + return int(st[:2]) + int(st[3:]) / 60 + def _get_employees(self, prop) -> SuperDict: """Returns a SuperDict with the employee id as key and the prop as value""" return self._get_property("employees", prop) @@ -358,13 +454,78 @@ def _get_horizon(self) -> int: """Returns the value of the horizon parameter""" return self.data["parameters"]["horizon"] - def _get_weekly_schedule(self): + def _get_weekly_schedule(self, round_ts=True): """Returns a SuperDict of days and the opening hours""" - return self.data["weekly_schedule"] + return self.data["weekly_schedule"].vapply( + lambda v: (v.vapply(lambda vv: self._format_hour_tuples(vv, round_ts))) + ) - def _get_schedule_exceptions(self): + def _get_schedule_exceptions(self, round_ts=True): """Returns a SuperDict of days and the opening hours""" - return self.data["schedule_exceptions"] + return self.data["schedule_exceptions"].vapply( + lambda v: (v.vapply(lambda vv: self._format_hour_tuples(vv, round_ts))) + ) + + def round_hour_string_down_to_tuple(self, hour_string): + """ + Returns a tuple (hours, minutes) with the hour and minutes + of the provided hour_string rounded to the lower time slot + For example: for hour_string = "12:45" and the slot_length being 30, returns 12, 30 + """ + ts_length = self._get_slot_length() + return int(hour_string[:2]), ts_length * (int(hour_string[3:]) // ts_length) + + def round_hour_string_up_to_tuple(self, hour_string): + """ + Returns a tuple (hours, minutes) with the hour and minutes + of the provided hour_string rounded to the upper time slot + For example: for hour_string = "12:45" and the slot_length being 30, returns 13, 0 + """ + ts_length = self._get_slot_length() + rounded_hour = int(hour_string[:2]) + rounded_minutes = ts_length * ceil(int(hour_string[3:]) / ts_length) + if rounded_hour != 23 and rounded_minutes == 60: + return rounded_hour + 1, 0 + elif rounded_hour == 23 and rounded_minutes == 60: + return 24, 0 + elif rounded_hour == 0 and rounded_minutes == 0: + return 24, 0 + return rounded_hour, rounded_minutes + + def _format_hour_tuples(self, tup, round_ts): + """ + Returns a tuple (hour, minutes, hour, minutes) with the hours and minutes of the provided + hour string, with the first hour string rounded down and the second rounded up. + For example: for tup = ("08:15", "19:45") and slot_length = 30, returns (8, 0, 20, 0) + """ + if round_ts: + rounded_hour_1 = self.round_hour_string_down_to_tuple(tup[0]) + rounded_hour_2 = self.round_hour_string_up_to_tuple(tup[1]) + else: + rounded_hour_1 = int(tup[0][:2]), int(tup[0][3:]) + rounded_hour_2 = int(tup[1][:2]), int(tup[1][3:]) + return ( + rounded_hour_1[0], + rounded_hour_1[1], + rounded_hour_2[0], + rounded_hour_2[1], + ) + + def _round_hour_string_down(self, hour_string): + """ + Returns an hour string with the hour rounded to the upper time slot. + For example: for hour_string = "12:45" and slot_length = 30, returns "12:30" + """ + hour, minutes = self.round_hour_string_down_to_tuple(hour_string) + return get_hour_string_from_hour_minute(hour, minutes) + + def _round_hour_string_up(self, hour_string): + """ + Returns an hour string with the hour rounded to the upper time slot. + For example: for hour_string = "12:45" and slot_length = 30, returns "13:00" + """ + hour, minutes = self.round_hour_string_up_to_tuple(hour_string) + return get_hour_string_from_hour_minute(hour, minutes) def _get_start_date(self) -> datetime: """Returns the datetime object of the starting date""" @@ -398,6 +559,10 @@ def _hour_to_slot(self, hours) -> int: """Converts from a hours to slots""" return int(hours * 60 / self._get_slot_length()) + def _minutes_to_slot(self, minutes) -> int: + """Converts from a hours to slots""" + return int(minutes / self._get_slot_length()) + def _get_employees_contracts(self) -> SuperDict[Tuple[int, int], int]: """ Returns a SuperDict with the week and employee tuple as key @@ -496,7 +661,7 @@ def _get_employees_contract_shift(self) -> SuperDict[Tuple[int, int], int]: contract_shift = self._get_contracts("id_shift") return self._get_employees_contracts().vapply(lambda c: contract_shift[c]) - def _get_employees_contract_starting_hour(self) -> SuperDict: + def _get_employees_contract_starting_hour(self, round_ts=True) -> SuperDict: """ Returns a SuperDict with the week and employee tuple as key and the shift starting hour @@ -504,9 +669,15 @@ def _get_employees_contract_starting_hour(self) -> SuperDict: For example: {(36, 1): 7, ...} """ start = self._get_shifts("start") + + if round_ts: + start = start.vapply(self._round_hour_string_down) + return self._get_employees_contract_shift().vapply(lambda s: start[s]) - def _get_employees_contract_ending_hour(self) -> SuperDict[Tuple[int, int], float]: + def _get_employees_contract_ending_hour( + self, round_ts=True + ) -> SuperDict[Tuple[int, int], float]: """ Returns a SuperDict with the week and employee tuple as key and the shift ending hour @@ -514,6 +685,9 @@ def _get_employees_contract_ending_hour(self) -> SuperDict[Tuple[int, int], floa For example: {(36, 1): 21, ...} """ end = self._get_shifts("end") + + if round_ts: + end = end.vapply(self._round_hour_string_up) return self._get_employees_contract_shift().vapply(lambda s: end[s]) def _get_employee_time_slots_week(self) -> TupList: @@ -523,8 +697,12 @@ def _get_employee_time_slots_week(self) -> TupList: For example: [("2021-09-06T07:00", 36, "2021-09-06", 1), ("2021-09-06T08:00", 36, "2021-09-06", 1), ...] """ - start = self._get_employees_contract_starting_hour() - end = self._get_employees_contract_ending_hour() + start = self._get_employees_contract_starting_hour().vapply( + lambda v: self._get_hour_from_hour_string(v) + ) + end = self._get_employees_contract_ending_hour().vapply( + lambda v: self._get_hour_from_hour_string(v) + ) return TupList( (self.get_time_slot_string(ts), w, self._get_date_string_from_ts(ts), e) @@ -731,7 +909,7 @@ def _filter_demand(self, ts) -> float: Given a time slot (date time) it returns the demand, if exists, zero otherwise """ return self._get_property("demand", "demand").get( - (self._get_date_string_from_ts(ts), self._get_hour_from_ts(ts)), 0 + (self._get_date_string_from_ts(ts), self._get_hour_string_from_ts(ts)), 0 ) def get_demand(self) -> SuperDict: @@ -751,7 +929,12 @@ def filter_skills_demand(self, ts, id_skill) -> int: Given a time slot (date time) and the id of a skill, returns the skill demand if it exists, zero otherwise """ return self._get_property("skill_demand", "demand").get( - (self._get_date_string_from_ts(ts), self._get_hour_from_ts(ts), id_skill), 0 + ( + self._get_date_string_from_ts(ts), + self._get_hour_string_from_ts(ts), + id_skill, + ), + 0, ) def get_ts_demand_employees_skill(self, e_availability) -> TupList: @@ -928,13 +1111,16 @@ def _get_employee_downtime_days(self) -> SuperDict: downtime_days_week = downtime_days.take([0, 1, 2]).to_dict(2) return SuperDict({k: sum(v) for k, v in downtime_days_week.items()}) - def _get_employee_preferences(self) -> TupList: + def _get_employee_preferences(self, round_ts=True) -> TupList: """ Returns a TupList with the employee preferences - For example: [(1, "2021-09-09", 5, 15), - (1, "2021-09-09", 5, 15), ...] + For example: [(1, "2021-09-09", 5, "15:00"), + (1, "2021-09-09", 5, "15:00"), ...] """ - return TupList((self.data["employee_preferences"].keys_tl())) + return TupList(self.data["employee_preferences"].keys_tl()).vapply_col( + 3, + lambda v: self._round_hour_string_up(v[3]) if round_ts else v[3], + ) def get_employee_time_slots_preferences(self) -> SuperDict: """ @@ -969,7 +1155,7 @@ def get_employee_preference_start_ts(self) -> SuperDict: (self.get_time_slot_string(ts), self._get_date_string_from_ts(ts), e) for ts in self.time_slots for e in self._get_employees("id") - if (e, self._get_date_string_from_ts(ts), self._get_hour_from_ts(ts)) + if (e, self._get_date_string_from_ts(ts), self._get_hour_string_from_ts(ts)) in preferences.take([0, 1, 3]) if (self.get_time_slot_string(ts), e) in availability ) diff --git a/cornflow-dags/DAG/rostering/core/solution.py b/cornflow-dags/DAG/rostering/core/solution.py index 7df549a6d..b23edecec 100644 --- a/cornflow-dags/DAG/rostering/core/solution.py +++ b/cornflow-dags/DAG/rostering/core/solution.py @@ -21,7 +21,6 @@ class Solution(SolutionCore): @classmethod def from_dict(cls, data: dict) -> "Solution": - data_p = { el: {(v["id_employee"], v["time_slot"]): v for v in data[el]} for el in ["works"] diff --git a/cornflow-dags/DAG/rostering/core/tools.py b/cornflow-dags/DAG/rostering/core/tools.py index 8daffd6bc..75515e084 100644 --- a/cornflow-dags/DAG/rostering/core/tools.py +++ b/cornflow-dags/DAG/rostering/core/tools.py @@ -14,17 +14,19 @@ def get_date_string_from_ts(ts: datetime) -> str: return datetime.strftime(ts, "%Y-%m-%d") -def get_date_string_from_ts_string(ts: str) -> str: - return ts[0:10] - - def get_hour_from_date_time(ts: datetime) -> float: """Returns the hours (in number) of the given time slot""" return float(ts.hour + ts.minute / 60) -def get_hour_from_string(string: str) -> float: - return get_hour_from_date_time(get_date_time_from_string(string)) +def get_hour_string_from_date_time(ts: datetime) -> str: + """Returns the hour string for the given time slot""" + return ts.strftime("%H:%M") + + +def get_hour_string_from_hour_minute(hour: int, minute: int) -> str: + """Returns the hour string for the given time slot""" + return str(hour).zfill(2) + ":" + str(minute).zfill(2) def get_one_date(starting_date: datetime, weeks: int = 0, days: int = 0) -> datetime: diff --git a/cornflow-dags/DAG/rostering/data/test_instance_1.json b/cornflow-dags/DAG/rostering/data/test_instance_1.json index 3232a1d65..09977cfb7 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_1.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_1.json @@ -25,20 +25,20 @@ { "id": 1, "name": "morning", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "afternoon", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "full_day", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -91,347 +91,347 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 30 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 40 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 35 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 30 } ], "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 15 + "starting_hour": "08:00", + "ending_hour": "15:00" }, { "week_day": 1, - "starting_hour": 15, - "ending_hour": 20 + "starting_hour": "15:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "schedule_exceptions": [ { "date": "2021-09-07", - "starting_hour": 8, - "ending_hour": 15 + "starting_hour": "08:00", + "ending_hour": "15:00" }, { "date": "2021-09-07", - "starting_hour": 15, - "ending_hour": 20 + "starting_hour": "15:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_2.json b/cornflow-dags/DAG/rostering/data/test_instance_2.json index 248696103..424aa8916 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_2.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_2.json @@ -30,20 +30,20 @@ { "id": 1, "name": "morning", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "afternoon", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "full_day", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -105,302 +105,302 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 30 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 40 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 35 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 30 } ], @@ -413,28 +413,28 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_3.json b/cornflow-dags/DAG/rostering/data/test_instance_3.json index 7633bbe6e..74120ce03 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_3.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_3.json @@ -25,20 +25,20 @@ { "id": 1, "name": "morning", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "afternoon", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "full_day", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -91,302 +91,302 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 30 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 40 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 35 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 30 } ], @@ -413,13 +413,13 @@ "skill_demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 } @@ -427,28 +427,28 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_4.json b/cornflow-dags/DAG/rostering/data/test_instance_4.json index 05ff25f6c..02d090dc3 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_4.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_4.json @@ -50,20 +50,20 @@ { "id": 1, "name": "Mañana", - "start": 6, - "end": 15 + "start": "06:00", + "end": "15:00" }, { "id": 2, "name": "Tarde", - "start": 13, - "end": 22 + "start": "13:00", + "end": "22:00" }, { "id": 3, "name": "Completo", - "start": 6, - "end": 22 + "start": "06:00", + "end": "22:00" } ], "contracts": [ @@ -152,330 +152,330 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 30 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 40 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 35 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 30 } ], "weekly_schedule": [ { "week_day": 1, - "starting_hour": 6, - "ending_hour": 22 + "starting_hour": "06:00", + "ending_hour": "22:00" }, { "week_day": 2, - "starting_hour": 6, - "ending_hour": 22 + "starting_hour": "06:00", + "ending_hour": "22:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_5.json b/cornflow-dags/DAG/rostering/data/test_instance_5.json index 957c85ec3..21e36a00b 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_5.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_5.json @@ -30,20 +30,20 @@ { "id": 1, "name": "morning", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "afternoon", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "full_day", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -105,302 +105,302 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 30 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 30 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 25 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 20 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 40 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 35 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 25 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 20 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 10 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 20 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 15 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 10 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 15 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 20 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 25 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 30 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 35 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 30 } ], @@ -421,28 +421,28 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_6.json b/cornflow-dags/DAG/rostering/data/test_instance_6.json index 61e52dbcd..6516a3768 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_6.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_6.json @@ -75,20 +75,20 @@ { "id": 1, "name": "Mañana", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "Tarde", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "Completo", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -346,22389 +346,22389 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 227 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 293 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 203 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 269 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 243 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 288 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 287 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 295 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 260 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 235 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 240 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 272 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 266 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 250 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 274 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 242 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 212 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 281 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 268 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 225 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 276 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 283 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 221 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 289 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 230 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 233 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 214 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 226 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 284 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 200 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 288 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 203 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 292 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 208 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 221 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 281 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 251 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 232 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 298 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 267 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 294 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 211 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 240 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 270 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 247 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 228 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 270 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 214 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 292 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 274 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 214 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 235 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 244 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 258 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 278 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 270 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 224 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 299 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 248 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 264 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 240 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 210 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 242 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 300 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 293 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 263 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 253 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 237 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 279 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 201 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 213 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 298 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 268 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 286 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 267 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 274 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 250 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 248 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 282 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 253 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 227 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 216 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 208 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 233 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 248 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 275 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 300 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 210 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 268 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 207 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 293 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 273 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 202 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 278 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 243 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 232 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 257 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 240 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 263 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 201 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 285 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 239 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 240 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 200 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 239 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 243 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 285 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 240 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 227 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 279 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 280 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 229 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 298 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 261 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 258 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 300 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 267 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 286 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 289 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 265 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 274 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 260 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 256 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 270 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 209 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 219 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 229 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 234 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 269 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 252 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 256 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 201 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 211 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 269 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 235 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 243 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 253 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 263 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 296 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 258 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 256 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 279 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 238 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 222 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 264 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 272 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 273 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 202 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 285 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 203 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 258 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 258 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 283 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 297 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 232 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 211 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 206 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 258 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 228 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 222 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 263 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 298 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 277 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 257 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 210 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 218 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 254 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 286 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 265 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 296 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 279 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 242 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 254 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 295 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 233 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 247 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 275 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 251 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 288 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 219 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 252 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 296 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 260 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 238 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 266 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 247 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 290 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 258 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 273 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 242 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 241 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 220 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 235 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 237 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 238 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 268 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 273 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 265 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 270 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 297 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 298 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 220 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 259 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 221 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 277 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 231 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 269 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 297 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 268 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 244 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 243 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 229 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 279 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 215 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 293 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 281 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 266 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 282 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 299 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 226 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 282 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 212 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 246 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 274 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 290 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 236 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 266 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 225 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 289 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 236 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 230 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 207 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 249 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 222 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 265 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 277 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 210 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 249 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 224 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 267 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 291 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 204 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 290 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 277 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 291 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 284 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 240 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 224 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 263 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 243 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 232 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 239 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 274 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 243 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 207 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 270 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 290 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 243 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 216 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 248 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 280 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 217 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 283 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 285 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 243 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 207 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 224 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 290 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 212 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 300 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 209 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 258 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 227 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 245 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 246 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 250 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 250 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 246 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 236 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 223 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 219 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 293 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 243 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 290 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 215 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 202 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 234 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 291 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 279 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 220 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 240 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 233 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 293 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 272 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 300 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 247 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 280 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 220 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 247 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 227 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 216 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 218 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 257 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 224 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 233 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 248 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 278 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 275 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 294 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 258 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 233 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 228 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 262 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 251 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 252 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 204 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 233 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 255 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 267 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 225 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 208 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 244 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 208 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 207 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 275 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 274 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 281 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 219 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 230 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 281 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 266 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 222 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 294 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 226 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 209 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 256 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 228 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 217 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 223 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 228 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 213 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 275 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 203 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 223 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 224 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 218 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 238 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 253 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 221 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 201 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 258 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 210 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 252 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 247 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 284 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 228 } ], "skill_demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-14", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-17", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-18", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-19", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-20", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-21", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-22", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-23", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-24", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-25", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-26", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-27", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-28", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-29", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-30", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-01", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-02", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-03", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-04", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-05", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-13", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-14", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-15", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-16", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-10-17", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 } @@ -22736,35 +22736,35 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "schedule_exceptions": [ { "date": "2021-09-07", - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_7.json b/cornflow-dags/DAG/rostering/data/test_instance_7.json index 3d4874717..cf1a74183 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_7.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_7.json @@ -75,20 +75,20 @@ { "id": 1, "name": "Mañana", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "Tarde", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "Completo", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -346,3734 +346,3734 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 227 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 293 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 203 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 269 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 243 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 288 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 287 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 295 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 260 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 235 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 240 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 272 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 266 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 250 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 274 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 242 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 212 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 281 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 268 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 225 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 276 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 283 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 221 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 289 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 230 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 233 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 214 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 226 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 284 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 200 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 288 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 203 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 292 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 208 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 221 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 281 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 251 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 232 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 298 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 267 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 294 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 211 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 240 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 270 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0 } ], "skill_demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 } @@ -4081,35 +4081,35 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "schedule_exceptions": [ { "date": "2021-09-07", - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "employee_preferences": [ @@ -4117,13 +4117,13 @@ "id_employee": 1, "day": "2021-09-07", "hours": 6, - "start": 14 + "start": "14:00" }, { "id_employee": 2, "day": "2021-09-08", "hours": 7, - "start": 8 + "start": "08:00" } ], "parameters": { diff --git a/cornflow-dags/DAG/rostering/data/test_instance_8.json b/cornflow-dags/DAG/rostering/data/test_instance_8.json index cdfca2ddd..9010ab646 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_8.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_8.json @@ -75,20 +75,20 @@ { "id": 1, "name": "Mañana", - "start": 8, - "end": 15 + "start": "08:00", + "end": "15:00" }, { "id": 2, "name": "Tarde", - "start": 13, - "end": 20 + "start": "13:00", + "end": "20:00" }, { "id": 3, "name": "Completo", - "start": 8, - "end": 20 + "start": "08:00", + "end": "20:00" } ], "contracts": [ @@ -346,3734 +346,3734 @@ "demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 227 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 293 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 203 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 269 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 243 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 288 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 287 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 295 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 260 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 235 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 240 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 272 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 266 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 250 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 275 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 274 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 242 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 212 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 281 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 268 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 225 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 276 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 283 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 221 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 289 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 230 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 233 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 297 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 214 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 226 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 284 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 207 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 200 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 288 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 203 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 292 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 208 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 221 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 281 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 251 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 232 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 298 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 267 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 241 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 294 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 211 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 240 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 270 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0 } ], "skill_demand": [ { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-06", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-07", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-08", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-09", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 9, + "hour": "09:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 11, + "hour": "11:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 14, + "hour": "14:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 15, + "hour": "15:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 16, + "hour": "16:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 1 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 5 }, { "day": "2021-09-10", - "hour": 20, + "hour": "20:00", "demand": 1, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-11", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 8, + "hour": "08:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 9, + "hour": "09:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 10, + "hour": "10:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 11, + "hour": "11:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 12, + "hour": "12:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 13, + "hour": "13:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 14, + "hour": "14:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 15, + "hour": "15:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 16, + "hour": "16:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 17, + "hour": "17:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 18, + "hour": "18:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 19, + "hour": "19:00", "demand": 0, "id_skill": 6 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 1 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 2 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 3 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 4 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 5 }, { "day": "2021-09-12", - "hour": 20, + "hour": "20:00", "demand": 0, "id_skill": 6 } @@ -4081,35 +4081,35 @@ "weekly_schedule": [ { "week_day": 1, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 2, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 3, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 4, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" }, { "week_day": 5, - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "schedule_exceptions": [ { "date": "2021-09-07", - "starting_hour": 8, - "ending_hour": 20 + "starting_hour": "08:00", + "ending_hour": "20:00" } ], "employee_preferences": [ @@ -4117,13 +4117,13 @@ "id_employee": 1, "day": "2021-09-07", "hours": 6, - "start": 14 + "start": "14:00" }, { "id_employee": 2, "day": "2021-09-08", "hours": 7, - "start": 8 + "start": "08:00" } ], "employee_holidays": [ @@ -4154,11 +4154,11 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": false, - "rq10": false, - "rq11": false, - "rq12": false, - "rq13": false, - "rq14": false + "rq09": true, + "rq10": true, + "rq11": true, + "rq12": true, + "rq13": true, + "rq14": true } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/schemas/instance.json b/cornflow-dags/DAG/rostering/schemas/instance.json index 3082a8bc0..35c56cc5e 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance.json +++ b/cornflow-dags/DAG/rostering/schemas/instance.json @@ -162,14 +162,14 @@ "start": { "description": "The earliest hour that an employee assigned to this shift can start working.", "title": "Starting hour", - "type": "integer", + "type": "string", "sortable": true, "filterable": true }, "end": { "description": "The latest hour that an employee assigned to this shift can stop working.", "title": "Ending hour", - "type": "integer", + "type": "string", "sortable": true, "filterable": true } @@ -276,7 +276,7 @@ "hour": { "description": "The hour of the demand.", "title": "Hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true }, @@ -315,14 +315,14 @@ "starting_hour": { "description": "The hour the work center opens", "title": "Opening hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true }, "ending_hour": { "description": "The hour the work center closes", "title": "Closing hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true } @@ -354,14 +354,14 @@ "starting_hour": { "description": "The hour the work center opens", "title": "Opening hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true }, "ending_hour": { "description": "The hour the work center closes", "title": "Closing hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true } @@ -449,7 +449,7 @@ "hour": { "description": "The hour of the skill demand.", "title": "Hour", - "type": "number", + "type": "string", "sortable": true, "filterable": true }, @@ -591,7 +591,7 @@ "start": { "description": "The start hour time.", "title": "Start", - "type": "integer", + "type": "string", "sortable": true, "filterable": true } diff --git a/cornflow-dags/DAG/rostering/schemas/instance_checks.json b/cornflow-dags/DAG/rostering/schemas/instance_checks.json index ad4fd4aa9..75fa7e70e 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance_checks.json +++ b/cornflow-dags/DAG/rostering/schemas/instance_checks.json @@ -25,7 +25,119 @@ "required": ["primary_table", "foreign_table", "key", "value"], "additionalProperties": false } + }, + "timeslot_length": { + "type": "object", + "title": "Timeslot length", + "is_warning": false, + "description": "Timeslot length should be 15, 30 or 60.", + "properties": { + "timeslot_length": { + "type": "number", + "title": "Timeslot length", + "description": "The timeslot length provided by the user." + } + }, + "required": [] + }, + "weekly_schedule_timeslots": { + "type": "array", + "title": "Weekly schedule timeslots", + "is_warning": true, + "description": "The hours provided in the weekly schedule table are not coherent with the timeslot length. The opening hours will be rounded to match timeslot length.", + "items": { + "type": "object", + "properties": { + "weekday": { + "type": "integer", + "title": "Weekday", + "description": "The day of the week" + }, + "hour": { + "type": "string", + "title": "Hour", + "description": "The hour of the incoherence" + } + }, + "required": ["weekday", "hour"] + } + }, + "schedule_exceptions_timeslots": { + "type": "array", + "title": "Schedule exceptions timeslots", + "is_warning": true, + "description": "The hours provided in the schedule exceptions table are not coherent with the timeslot length. The opening hours will be rounded to match timeslot length.", + "items": { + "type": "object", + "properties": { + "date": { + "type": "integer", + "title": "Date", + "description": "The date of the problem" + }, + "hour": { + "type": "string", + "title": "Hour", + "description": "The hour of the incoherence" + } + }, + "required": ["date", "hour"] + } + }, + "shift_hours_timeslots": { + "type": "array", + "title": "Contracts timeslots", + "is_warning": true, + "description": "The hours provided in the contracts table are not coherent with the timeslot length. The opening hours will be rounded to match timeslot length.", + "items": { + "type": "object", + "properties": { + "date": { + "type": "integer", + "title": "Date", + "description": "The date of the problem" + }, + "employee": { + "type": "integer", + "title": "Employee", + "description": "The employee with the problem" + }, + "hour": { + "type": "string", + "title": "Hour", + "description": "The hour of the incoherence" + } + }, + "required": ["week", "employee", "hour"] + } + }, + "employee_preferences_timeslots": { + "type": "array", + "title": "Employee preferences timeslots", + "is_warning": true, + "description": "The hours provided in the employees preferences table are not coherent with the timeslot length. The opening hours will be rounded to match timeslot length.", + "items": { + "type": "object", + "properties": { + "week": { + "type": "integer", + "title": "Week", + "description": "The week of the problem" + }, + "employee": { + "type": "integer", + "title": "Employee", + "description": "The employee with the problem" + }, + "hour": { + "type": "string", + "title": "Hour", + "description": "The hour of the incoherence" + } + }, + "required": ["week", "employee", "hour"] + } } }, - "required": ["incoherent_foreign_keys"] + "required": [] } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/solvers/mip_model.py b/cornflow-dags/DAG/rostering/solvers/mip_model.py index 989f0103f..b853c0857 100644 --- a/cornflow-dags/DAG/rostering/solvers/mip_model.py +++ b/cornflow-dags/DAG/rostering/solvers/mip_model.py @@ -47,7 +47,6 @@ def __init__(self, instance, solution=None): self.initialize() def solve(self, options: dict) -> dict: - model = pl.LpProblem("rostering", pl.LpMaximize) # Variables: self.create_variables() @@ -62,7 +61,9 @@ def solve(self, options: dict) -> dict: solver_name = "PULP_CBC_CMD" options["solver"] = f"{prefix}.{solver_name}" - solver = pl.getSolver(solver_name, **self.get_solver_config(options, lib="pulp")) + solver = pl.getSolver( + solver_name, **self.get_solver_config(options, lib="pulp") + ) # Solver and solve status = model.solve(solver) @@ -111,7 +112,6 @@ def initialize(self): self.preference_slots = self.instance.get_employee_time_slots_preferences() def create_variables(self): - self.works = pl.LpVariable.dicts( "works", self.employee_ts_availability, @@ -158,7 +158,7 @@ def create_constraints(self, model): ) # RQ04A: starts if does not work in one ts but in the next it does - for (ts, ts2, e) in self.ts_ts_employee: + for ts, ts2, e in self.ts_ts_employee: model += self.works[ts, e] >= self.works[ts2, e] - self.starts[ts2, e] # RQ04B: starts on first time slot @@ -185,7 +185,7 @@ def create_constraints(self, model): ) # RQ07: employees at least have to rest an amount of hours between working days. - for (ts, ts2, e) in self.incompatible_ts_employee: + for ts, ts2, e in self.incompatible_ts_employee: model += self.works[ts, e] + self.works[ts2, e] <= 1 # RQ08: a manager has to be working at all times diff --git a/cornflow-dags/DAG/two_dimension_bin_packing/core/experiment.py b/cornflow-dags/DAG/two_dimension_bin_packing/core/experiment.py index 1877c1cf9..479d1535b 100644 --- a/cornflow-dags/DAG/two_dimension_bin_packing/core/experiment.py +++ b/cornflow-dags/DAG/two_dimension_bin_packing/core/experiment.py @@ -1,15 +1,25 @@ import os +import sys from typing import Dict from cornflow_client import ExperimentCore from cornflow_client.core.tools import load_json -from matplotlib import pyplot as plt -from matplotlib.collections import PatchCollection -from matplotlib.patches import Rectangle from pytups import SuperDict + from .instance import Instance from .solution import Solution +try: + from matplotlib import pyplot as plt + from matplotlib.collections import PatchCollection + from matplotlib.patches import Rectangle +except ModuleNotFoundError: + pass +except NameError: + pass +except ImportError: + pass + class Experiment(ExperimentCore): schema_checks = load_json( @@ -43,6 +53,11 @@ def check_solution(self, *args, **kwargs) -> Dict[str, Dict]: return dict() def plot_solution(self): + if "matplotlib" not in sys.modules: + raise ModuleNotFoundError( + "Matplotlib has to be installed to be able to plot!" + ) + rectangles = [ Rectangle( (el["x"], el["y"]), diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 613a12cfb..1c0105fd1 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -8,4 +8,4 @@ ortools<=9.7.2996 xmltodict<=0.13.0 openpyxl<=3.1.2 pyomo<=6.6.2 -tsplib95<=0.7.1 \ No newline at end of file +tsplib95<=0.7.1 From 0297b792c5bfee2d6111590cb4cc2c2e05268c13 Mon Sep 17 00:00:00 2001 From: marioncottard <86973971+marioncottard@users.noreply.github.com> Date: Wed, 4 Oct 2023 17:52:25 +0200 Subject: [PATCH 04/22] Feature/rostering soft constraints (#464) * Changed all hours from int to string * Soft constraints * Deleted methods that are in InstanceSolutionCore * Added output checks, Applied formatter * Cleaning * Updated readme * Cleaning * Docstrings * Adjustements for 24/7 store * Cleaning * Updated solution files * Fixed clients tests * Post merge changes * Undo changes * Small changes rostering --------- Co-authored-by: Guillermo Gonzalez-Santander --- cornflow-dags/DAG/rostering/README.rst | 24 +- .../DAG/rostering/core/experiment.py | 120 ++++++++ cornflow-dags/DAG/rostering/core/instance.py | 119 ++++++-- cornflow-dags/DAG/rostering/core/solution.py | 11 +- cornflow-dags/DAG/rostering/core/tools.py | 33 --- .../DAG/rostering/data/test_instance_1.json | 30 +- .../DAG/rostering/data/test_instance_2.json | 30 +- .../DAG/rostering/data/test_instance_3.json | 30 +- .../DAG/rostering/data/test_instance_4.json | 30 +- .../DAG/rostering/data/test_instance_5.json | 30 +- .../DAG/rostering/data/test_instance_6.json | 32 +- .../DAG/rostering/data/test_instance_7.json | 30 +- .../DAG/rostering/data/test_instance_8.json | 30 +- .../DAG/rostering/data/test_solution_1.json | 278 +++++++++--------- .../DAG/rostering/data/test_solution_3.json | 278 +++++++++--------- .../DAG/rostering/schemas/instance.json | 134 ++++++++- .../rostering/schemas/instance_checks.json | 17 ++ .../rostering/schemas/solution_checks.json | 170 +++++++++++ .../DAG/rostering/solvers/mip_model.py | 250 ++++++++++++++-- .../cornflow_client/core/instance_solution.py | 2 +- .../unit/test_instance_solution_methods.py | 2 +- 21 files changed, 1241 insertions(+), 439 deletions(-) diff --git a/cornflow-dags/DAG/rostering/README.rst b/cornflow-dags/DAG/rostering/README.rst index 1669e72fa..63bf07bc0 100644 --- a/cornflow-dags/DAG/rostering/README.rst +++ b/cornflow-dags/DAG/rostering/README.rst @@ -47,11 +47,19 @@ Parameters - Minimum working hours: the minimum amount of hours that have to be worked each day that the employee works. - Slot length: the length of each time slot in minutes. -- Requirements: table indicating which requirements should be complied and which not - - - rq09: true or false if the skills requirement has to be applied - - rq10: true or false if the employee holidays requirement has to be applied - - rq11: true or false if the store holidays requirement has to be applied - - rq12: true or false if the employee downtime requirement has to be applied - - rq13: true or false if the employee preferences requirement has to be applied - - rq14: true or false if the employee max preference hours requirement has to be applied \ No newline at end of file +- Requirements: table indicating which requirements should be complied and which not, and if they are, if they should be applied as strict or soft constraints. + + - rq02: "soft", "strict" or "deactivated for the weekly hours constraint + - rq03: "soft", "strict" or "deactivated for the maximum daily hours constraint + - rq05: "soft", "strict" or "deactivated for the maximum days worked per week constraint + - rq06: "soft", "strict" or "deactivated for the minimum daily hours constraint + - rq07: "soft", "strict" or "deactivated for the minimum rest hours between shifts constraint + - rq08: "soft", "strict" or "deactivated for the constraint about needing to have a manager in the store at all times + - rq09: "soft", "strict" or "deactivated for the skills constraint + - rq10: "soft", "strict" or "deactivated for the employees' holidays constraint + - rq11: "strict" or "deactivated for the store holidays constraint + - rq12: "strict" or "deactivated for the employee downtime constraint + - rq13: "soft", "strict" or "deactivated for the employee start hour preferences constraint + - rq14: "soft", "strict" or "deactivated for the employee max preference hours constraint + +- Penalties: table indicating for each soft constraint the penalty level when it is not respected. \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/core/experiment.py b/cornflow-dags/DAG/rostering/core/experiment.py index dc282cafb..624e272d9 100644 --- a/cornflow-dags/DAG/rostering/core/experiment.py +++ b/cornflow-dags/DAG/rostering/core/experiment.py @@ -43,6 +43,12 @@ def check_solution(self, *args, **kwargs) -> dict: difference_hours_worked=self.check_hours_worked(), manager_present=self.check_manager_present(), skills_demand=self.check_skills_demand(), + days_worked_per_week=self.check_days_worked_per_week(), + min_hours_worked_per_day=self.check_min_hours_worked_day(), + employee_holidays=self.check_employee_holidays(), + employee_downtime=self.check_employees_downtime(), + start_hour_preference=self.check_start_hour_preference(), + number_hours_preferences=self.check_number_hours_preference(), ).vfilter(lambda v: len(v)) def get_objective(self) -> float: @@ -141,6 +147,120 @@ def check_skills_demand(self) -> list: else: return TupList([]) + def check_days_worked_per_week(self): + """Checks if an employee works more days than the number of days on their contract""" + max_working_slots_week = self.instance.get_max_working_days() + + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col( + None, + lambda v: self.instance.get_week_from_ts( + self.instance.get_datetime_from_string(v[0]) + ), + ) + .to_dict(result_col=0, indices=[2, 1]) + .vapply(lambda v: len(v.vapply(lambda vv: vv[:10]).unique())) + .kvfilter(lambda k, v: v > max_working_slots_week[k]) + .to_tuplist() + .vapply( + lambda v: { + "week": v[0], + "id_employee": v[1], + "nb_days_worked": v[2], + "max_days_week": max_working_slots_week[v[0], v[1]], + } + ) + ) + + def check_min_hours_worked_day(self): + """Checks if an employee works less than the minimum hours""" + min_worked_ts_day = self.instance.get_min_working_slots_day() + + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col(None, lambda v: v[0][:10]) + .to_dict(result_col=[0], indices=[2, 1]) + .vapply(lambda v: len(v)) + .kvfilter(lambda k, v: v < min_worked_ts_day[k]) + .to_tuplist() + .vapply( + lambda v: { + "date": v[0], + "id_employee": v[1], + "nb_hours_worked": self.instance.slot_to_hour(v[2]), + "min_hours_day": self.instance.slot_to_hour( + min_worked_ts_day[v[0], v[1]] + ), + } + ) + ) + + def check_employee_holidays(self): + """Checks that no employee works on their holidays""" + ts_employee_holidays = self.instance.get_employee_time_slots_holidays() + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vfilter(lambda v: v in ts_employee_holidays) + .vapply_col(None, lambda v: v[0][:10]) + .vapply(lambda v: {"date": v[2], "id_employee": v[1]}) + ) + + def check_employees_downtime(self): + """Checks that no employee works on their downtime""" + employee_downtime = self.instance._get_employee_downtime() + + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col(None, lambda v: v[0][:10]) + .unique() + .take([1, 2]) + .vfilter(lambda v: v in employee_downtime) + .vapply(lambda v: {"date": v[1], "id_employee": v[0]}) + ) + + def check_start_hour_preference(self): + """Checks that start hour preferences are respected""" + start_preferences = self.instance.get_employee_preference_start_ts() + + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col(None, lambda v: v[0][:10]) + .to_dict(result_col=0, indices=[2, 1]) + .vapply(lambda v: min(v)) + .kvfilter(lambda k, v: v not in start_preferences.get(k, [v])) + .to_tuplist() + .vapply( + lambda v: {"date": v[0], "id_employee": v[1], "start_hour": v[2][11:]} + ) + ) + + def check_number_hours_preference(self): + """Checks that the preferred number of hours worked is respected""" + preference_hours_employee = self.instance.get_employee_preference_hours() + + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col(None, lambda v: v[0][:10]) + .to_dict(result_col=0, indices=[2, 1]) + .vapply(lambda v: self.instance.slot_to_hour(len(v))) + .kvfilter(lambda k, v: v > preference_hours_employee.get(k, v)) + .to_tuplist() + .vapply( + lambda v: { + "date": v[0], + "id_employee": v[1], + "number_hours_worked": v[2], + } + ) + ) + def get_one_employee_percentage(self) -> float: """Returns the percentage of time slots where only one employee is working""" ts_employee = self.solution.get_ts_employee() diff --git a/cornflow-dags/DAG/rostering/core/instance.py b/cornflow-dags/DAG/rostering/core/instance.py index 474d176a1..d3cb1591a 100644 --- a/cornflow-dags/DAG/rostering/core/instance.py +++ b/cornflow-dags/DAG/rostering/core/instance.py @@ -1,29 +1,26 @@ """ """ -# Imports from libraries -from datetime import datetime, timedelta import os import pickle -from pytups import SuperDict, TupList -from typing import Dict, Tuple + +# Imports from libraries +from datetime import datetime, timedelta from math import ceil +from typing import Dict, Tuple # Imports from cornflow libraries from cornflow_client import InstanceCore from cornflow_client.core.tools import load_json +from pytups import SuperDict, TupList + from .const import INSTANCE_KEYS_RELATION # Imports from internal modules from .tools import ( - get_date_from_string, - get_date_string_from_ts, - get_hour_from_date_time, get_hour_string_from_date_time, get_hour_string_from_hour_minute, get_one_date, - get_time_slot_string, - get_week_from_ts, ) @@ -76,6 +73,7 @@ def from_dict(cls, data: dict) -> "Instance": data_p["parameters"] = pickle.loads(pickle.dumps(data["parameters"], -1)) data_p["requirements"] = pickle.loads(pickle.dumps(data["requirements"], -1)) + data_p["penalties"] = pickle.loads(pickle.dumps(data["penalties"], -1)) if data.get("skill_demand"): data_p["skill_demand"] = { @@ -146,6 +144,7 @@ def to_dict(self) -> Dict: data_p["parameters"] = self.data["parameters"] data_p["requirements"] = self.data["requirements"] + data_p["penalties"] = self.data["penalties"] data_p["weekly_schedule"] = [ {"week_day": d, "starting_hour": h_ini, "ending_hour": h_end} @@ -195,6 +194,7 @@ def check(self) -> dict: return SuperDict( incoherent_foreign_keys=self.check_indexes_coherence(), timeslot_length=self.check_timeslot_length(), + penalties=self.check_penalties(), **self.check_timeslot_coherence(), ).vfilter(lambda v: len(v)) @@ -290,6 +290,16 @@ def check_timeslot_coherence(self): return checks.vfilter(lambda v: len(v)) + def check_penalties(self): + """Checks that all penalties are defined for soft constraints""" + penalties = self.get_penalties().keys_l() + return ( + self.get_requirements() + .kvfilter(lambda k, v: v == "soft" and k not in penalties) + .keys_tl() + .vapply(lambda v: {"requirement": v}) + ) + def _get_weeks(self) -> TupList: """ Returns a TupList with the starting date of each week in date time format @@ -332,8 +342,8 @@ def _get_dates_properties(self) -> SuperDict: return SuperDict( { date: { - "string": get_date_string_from_ts(date), - "week": get_week_from_ts(date), + "string": self.get_date_string_from_ts(date), + "week": self.get_week_from_ts(date), } for date in self.dates } @@ -373,16 +383,17 @@ def _get_time_slots(self) -> TupList: ) .vfilter( # Remove schedule exceptions. - lambda v: get_date_string_from_ts(v) + lambda v: self.get_date_string_from_ts(v) not in self._get_schedule_exceptions() ) .vfilter( - lambda v: get_date_string_from_ts(v) not in self._get_store_holidays() + lambda v: self.get_date_string_from_ts(v) + not in self._get_store_holidays() ) ) ts_schedule_exceptions = TupList( - get_date_from_string(d) + self.get_date_from_string(d) + timedelta(hours=h_start, minutes=m_start + self._get_slot_length() * x) for d, value in self._get_schedule_exceptions().items() for (h_start, m_start, h_end, m_end) in value @@ -404,10 +415,10 @@ def _get_time_slots_properties(self) -> SuperDict: return SuperDict( { ts: { - "string": get_time_slot_string(ts), - "date": get_date_string_from_ts(ts), - "week": get_week_from_ts(ts), - "hour": get_hour_from_date_time(ts), + "string": self.get_datetime_string_from_ts(ts), + "date": self.get_date_string_from_ts(ts), + "week": self.get_week_from_ts(ts), + "hour": self.get_hour_from_ts(ts), "hour_string": get_hour_string_from_date_time(ts), } for ts in self.time_slots @@ -529,7 +540,7 @@ def _round_hour_string_up(self, hour_string): def _get_start_date(self) -> datetime: """Returns the datetime object of the starting date""" - return get_date_from_string(self.data["parameters"]["starting_date"]) + return self.get_date_from_string(self.data["parameters"]["starting_date"]) def _get_end_date(self) -> datetime: """Returns the last date in the horizon""" @@ -570,7 +581,7 @@ def _get_employees_contracts(self) -> SuperDict[Tuple[int, int], int]: Contracts are supposed to start on Monday and end on Sunday For example: {(36, 1): 10, ...} """ - default_date = get_date_string_from_ts(self._get_end_date()) + default_date = self.get_date_string_from_ts(self._get_end_date()) contract_start = self._get_contracts("start_contract") contract_end = self._get_contracts("end_contract").vapply( @@ -733,6 +744,33 @@ def get_employees_time_slots_day(self) -> SuperDict: """ return self._get_employee_time_slots_week().take([0, 2, 3]).to_dict(0) + def get_employee_time_slots_holidays(self) -> TupList: + """ + Returns a TupList with the combinations of employees and timeslots + in which the employees are on holidays. + For example: [("2021-09-06T07:00", 1), + ("2021-09-06T08:00", 1), ...] + """ + start = self._get_employees_contract_starting_hour().vapply( + lambda v: self._get_hour_from_hour_string(v) + ) + end = self._get_employees_contract_ending_hour().vapply( + lambda v: self._get_hour_from_hour_string(v) + ) + + return TupList( + (self.get_time_slot_string(ts), e) + for ts in self.time_slots + for (w, e) in start + if self._get_week_from_ts(ts) == w + and start[w, e] <= self._get_hour_from_ts(ts) < end[w, e] + and (e, self._get_date_string_from_ts(ts)) + in self._get_employee_holidays(model=True) + and (e, self._get_date_string_from_ts(ts)) + not in self._get_employee_downtime() + if self._get_date_string_from_ts(ts) not in self._get_store_holidays() + ) + def get_consecutive_time_slots_employee(self) -> TupList: """ Returns a TupList with a time slot, the nex time slot in the same day @@ -937,7 +975,7 @@ def filter_skills_demand(self, ts, id_skill) -> int: 0, ) - def get_ts_demand_employees_skill(self, e_availability) -> TupList: + def get_ts_demand_employees_skill(self, e_availability) -> SuperDict: """ Returns a TupList with the combinations of: - Time slots @@ -959,13 +997,26 @@ def get_ts_demand_employees_skill(self, e_availability) -> TupList: } ).kvapply(lambda k, v: [e for e in v if (k[0], e) in e_availability]) - def _get_employee_holidays(self) -> TupList: + @staticmethod + def get_ts_skill_demand(ts_demand_employees_skill): + """ + Returns a TupList with the combinations of skills and timeslots when those + skills are needed. + For example: [("2021-09-06T07:00", 1), ("2021-09-06T08:00", 2), ...] + """ + return ( + ts_demand_employees_skill.take([0, 1]).unique2().vapply(lambda v: tuple(v)) + ) + + def _get_employee_holidays(self, model=False) -> TupList: """ Returns a TupList with the combinations of employees and holiday days. For example: [(1, "2021-09-06"), (2, "2021-09-07"), ...] """ - if self.get_requirement("rq10"): + if self.get_requirement("rq10") == "strict" or ( + self.get_requirement("rq10") == "soft" and model + ): return TupList(self.data["employee_holidays"].keys_tl()) else: return TupList([]) @@ -1015,7 +1066,7 @@ def _get_store_holidays(self) -> TupList: For example: [("2021-09-06"), ("2021-09-07"), ...] """ - if self.get_requirement("rq11"): + if self.get_requirement("rq11") != "deactivated": return TupList(self.data["store_holidays"].keys_tl()) else: return TupList([]) @@ -1067,7 +1118,7 @@ def _get_employee_downtime(self) -> TupList: For example: [(1, "2021-09-06"), (2, "2021-09-07"), ...] """ - if self.get_requirement("rq12"): + if self.get_requirement("rq12") != "deactivated": return TupList(self.data["employee_downtime"].keys_tl()) else: return TupList([]) @@ -1178,3 +1229,21 @@ def get_requirement(self, rq): Returns the activation value of a given requirement """ return self.data["requirements"].get(rq, True) + + def get_requirements(self): + """ + Returns the activation values of the requirements + """ + return self.data["requirements"] + + def get_penalty(self, rq): + """ + Returns the penalty value of a given requirement + """ + return (self.get_requirement(rq) == "soft") * self.data["penalties"].get(rq, 1) + + def get_penalties(self): + """ + Returns the penalties values of the requirement + """ + return self.data["penalties"] diff --git a/cornflow-dags/DAG/rostering/core/solution.py b/cornflow-dags/DAG/rostering/core/solution.py index b23edecec..2a281cf05 100644 --- a/cornflow-dags/DAG/rostering/core/solution.py +++ b/cornflow-dags/DAG/rostering/core/solution.py @@ -4,14 +4,11 @@ # Imports from libraries import os import pickle -from pytups import SuperDict, TupList # Imports from cornflow libraries from cornflow_client import SolutionCore from cornflow_client.core.tools import load_json - -# Imports from internal modules -from .tools import get_week_from_string +from pytups import SuperDict, TupList class Solution(SolutionCore): @@ -62,7 +59,11 @@ def get_hours_worked_per_week(self) -> SuperDict: """ return ( TupList( - {"id_employee": id_employee, "ts": ts, "week": get_week_from_string(ts)} + { + "id_employee": id_employee, + "ts": ts, + "week": self.get_week_from_datetime_string(ts), + } for (id_employee, ts) in self.data["works"] ) .to_dict(result_col="ts", indices=["week", "id_employee"]) diff --git a/cornflow-dags/DAG/rostering/core/tools.py b/cornflow-dags/DAG/rostering/core/tools.py index 75515e084..22f6afcfb 100644 --- a/cornflow-dags/DAG/rostering/core/tools.py +++ b/cornflow-dags/DAG/rostering/core/tools.py @@ -1,24 +1,6 @@ from datetime import datetime, timedelta -def get_date_from_string(string: str) -> datetime: - return datetime.strptime(string, "%Y-%m-%d") - - -def get_date_time_from_string(string: str) -> datetime: - return datetime.strptime(string, "%Y-%m-%dT%H%M") - - -def get_date_string_from_ts(ts: datetime) -> str: - """Returns the string of a given date""" - return datetime.strftime(ts, "%Y-%m-%d") - - -def get_hour_from_date_time(ts: datetime) -> float: - """Returns the hours (in number) of the given time slot""" - return float(ts.hour + ts.minute / 60) - - def get_hour_string_from_date_time(ts: datetime) -> str: """Returns the hour string for the given time slot""" return ts.strftime("%H:%M") @@ -32,18 +14,3 @@ def get_hour_string_from_hour_minute(hour: int, minute: int) -> str: def get_one_date(starting_date: datetime, weeks: int = 0, days: int = 0) -> datetime: """Returns a date from a starting date adding weeks and days""" return starting_date + timedelta(days=weeks * 7 + days) - - -def get_time_slot_string(ts: datetime) -> str: - """Returns the string of a given time slot""" - return datetime.strftime(ts, "%Y-%m-%dT%H%M") - - -def get_week_from_string(string: str) -> int: - """ "Returns the integer value of the week for the given string""" - return get_week_from_ts(get_date_time_from_string(string)) - - -def get_week_from_ts(ts: datetime) -> int: - """Returns the integer value of the week for the given time slot""" - return ts.isocalendar()[1] diff --git a/cornflow-dags/DAG/rostering/data/test_instance_1.json b/cornflow-dags/DAG/rostering/data/test_instance_1.json index 09977cfb7..b3e3f3231 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_1.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_1.json @@ -442,11 +442,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_2.json b/cornflow-dags/DAG/rostering/data/test_instance_2.json index 424aa8916..748092b54 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_2.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_2.json @@ -445,11 +445,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_3.json b/cornflow-dags/DAG/rostering/data/test_instance_3.json index 74120ce03..d879f8927 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_3.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_3.json @@ -459,11 +459,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_4.json b/cornflow-dags/DAG/rostering/data/test_instance_4.json index 02d090dc3..0f5c75fa7 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_4.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_4.json @@ -486,11 +486,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_5.json b/cornflow-dags/DAG/rostering/data/test_instance_5.json index 21e36a00b..8dbeae129 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_5.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_5.json @@ -453,11 +453,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_6.json b/cornflow-dags/DAG/rostering/data/test_instance_6.json index 6516a3768..c45f4cd13 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_6.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_6.json @@ -22774,12 +22774,30 @@ "min_working_hours": 4, "min_resting_hours": 12 }, - "requirements": { - "rq09": false, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": false, - "rq14": false + "requirements": { + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "deactivated", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "deactivated", + "rq14": "deactivated" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_7.json b/cornflow-dags/DAG/rostering/data/test_instance_7.json index cf1a74183..b900b8fff 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_7.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_7.json @@ -4134,11 +4134,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 1, + "rq03": 1, + "rq05": 1, + "rq06": 1, + "rq07": 4, + "rq08": 2, + "rq09": 2, + "rq10": 1, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_8.json b/cornflow-dags/DAG/rostering/data/test_instance_8.json index 9010ab646..a8989894f 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_8.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_8.json @@ -4154,11 +4154,29 @@ "min_resting_hours": 12 }, "requirements": { - "rq09": true, - "rq10": true, - "rq11": true, - "rq12": true, - "rq13": true, - "rq14": true + "rq02": "strict", + "rq03": "strict", + "rq05": "strict", + "rq06": "strict", + "rq07": "strict", + "rq08": "strict", + "rq09": "strict", + "rq10": "strict", + "rq11": "strict", + "rq12": "strict", + "rq13": "soft", + "rq14": "soft" + }, + "penalties": { + "rq02": 4, + "rq03": 4, + "rq05": 5, + "rq06": 4, + "rq07": 5, + "rq08": 3, + "rq09": 1, + "rq10": 5, + "rq13": 1, + "rq14": 1 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_solution_1.json b/cornflow-dags/DAG/rostering/data/test_solution_1.json index 35d442941..c405bbd2a 100644 --- a/cornflow-dags/DAG/rostering/data/test_solution_1.json +++ b/cornflow-dags/DAG/rostering/data/test_solution_1.json @@ -1,551 +1,555 @@ { "indicators": { - "fo": 136 + "objective_function": 136, + "only_one_employee_percentage": 40.0, + "mean_demand": 10.152777777777779, + "max_demand": 15.0, + "min_demand": 5.0 }, "works": [ { "id_employee": 4, - "time_slot": "2021-09-06T0800" + "time_slot": "2021-09-06T08:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T0900" + "time_slot": "2021-09-06T09:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1000" + "time_slot": "2021-09-06T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1600" + "time_slot": "2021-09-06T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1600" + "time_slot": "2021-09-06T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1700" + "time_slot": "2021-09-06T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1800" + "time_slot": "2021-09-06T18:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1900" + "time_slot": "2021-09-06T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T0800" + "time_slot": "2021-09-07T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T0900" + "time_slot": "2021-09-07T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1000" + "time_slot": "2021-09-07T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1800" + "time_slot": "2021-09-07T18:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1900" + "time_slot": "2021-09-07T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T0800" + "time_slot": "2021-09-08T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T0900" + "time_slot": "2021-09-08T09:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1000" + "time_slot": "2021-09-08T10:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1000" + "time_slot": "2021-09-08T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1800" + "time_slot": "2021-09-08T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1800" + "time_slot": "2021-09-08T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1900" + "time_slot": "2021-09-08T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T0800" + "time_slot": "2021-09-09T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T0900" + "time_slot": "2021-09-09T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1000" + "time_slot": "2021-09-09T10:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1100" + "time_slot": "2021-09-09T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1200" + "time_slot": "2021-09-09T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1700" + "time_slot": "2021-09-09T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1700" + "time_slot": "2021-09-09T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1800" + "time_slot": "2021-09-09T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1900" + "time_slot": "2021-09-09T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T0800" + "time_slot": "2021-09-10T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T0900" + "time_slot": "2021-09-10T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1000" + "time_slot": "2021-09-10T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" } ] } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_solution_3.json b/cornflow-dags/DAG/rostering/data/test_solution_3.json index a05bca9fa..ea8ac174b 100644 --- a/cornflow-dags/DAG/rostering/data/test_solution_3.json +++ b/cornflow-dags/DAG/rostering/data/test_solution_3.json @@ -1,551 +1,555 @@ { "indicators": { - "fo": 136 + "objective_function": 136, + "only_one_employee_percentage": 36.666666666666664, + "mean_demand": 9.965277777777779, + "max_demand": 15.0, + "min_demand": 5.0 }, "works": [ { "id_employee": 1, - "time_slot": "2021-09-06T0800" + "time_slot": "2021-09-06T08:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T0900" + "time_slot": "2021-09-06T09:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1000" + "time_slot": "2021-09-06T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1100" + "time_slot": "2021-09-06T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1200" + "time_slot": "2021-09-06T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1300" + "time_slot": "2021-09-06T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1400" + "time_slot": "2021-09-06T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1500" + "time_slot": "2021-09-06T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1600" + "time_slot": "2021-09-06T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1600" + "time_slot": "2021-09-06T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-06T1700" + "time_slot": "2021-09-06T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1700" + "time_slot": "2021-09-06T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1800" + "time_slot": "2021-09-06T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-06T1900" + "time_slot": "2021-09-06T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T0800" + "time_slot": "2021-09-07T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T0900" + "time_slot": "2021-09-07T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1000" + "time_slot": "2021-09-07T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1100" + "time_slot": "2021-09-07T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1200" + "time_slot": "2021-09-07T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1300" + "time_slot": "2021-09-07T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1400" + "time_slot": "2021-09-07T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1500" + "time_slot": "2021-09-07T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1600" + "time_slot": "2021-09-07T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1700" + "time_slot": "2021-09-07T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1800" + "time_slot": "2021-09-07T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-07T1800" + "time_slot": "2021-09-07T18:00" }, { "id_employee": 3, - "time_slot": "2021-09-07T1900" + "time_slot": "2021-09-07T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T0800" + "time_slot": "2021-09-08T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T0900" + "time_slot": "2021-09-08T09:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1000" + "time_slot": "2021-09-08T10:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1000" + "time_slot": "2021-09-08T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1100" + "time_slot": "2021-09-08T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1200" + "time_slot": "2021-09-08T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1300" + "time_slot": "2021-09-08T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1400" + "time_slot": "2021-09-08T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1500" + "time_slot": "2021-09-08T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1600" + "time_slot": "2021-09-08T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1700" + "time_slot": "2021-09-08T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-08T1800" + "time_slot": "2021-09-08T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1800" + "time_slot": "2021-09-08T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-08T1900" + "time_slot": "2021-09-08T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T0800" + "time_slot": "2021-09-09T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T0900" + "time_slot": "2021-09-09T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1000" + "time_slot": "2021-09-09T10:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1100" + "time_slot": "2021-09-09T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1200" + "time_slot": "2021-09-09T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1300" + "time_slot": "2021-09-09T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1400" + "time_slot": "2021-09-09T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1500" + "time_slot": "2021-09-09T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1600" + "time_slot": "2021-09-09T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1700" + "time_slot": "2021-09-09T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-09T1700" + "time_slot": "2021-09-09T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1800" + "time_slot": "2021-09-09T18:00" }, { "id_employee": 1, - "time_slot": "2021-09-09T1900" + "time_slot": "2021-09-09T19:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T0800" + "time_slot": "2021-09-10T08:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T0900" + "time_slot": "2021-09-10T09:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1000" + "time_slot": "2021-09-10T10:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1100" + "time_slot": "2021-09-10T11:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1200" + "time_slot": "2021-09-10T12:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1300" + "time_slot": "2021-09-10T13:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 2, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1400" + "time_slot": "2021-09-10T14:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1500" + "time_slot": "2021-09-10T15:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1600" + "time_slot": "2021-09-10T16:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1700" + "time_slot": "2021-09-10T17:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1800" + "time_slot": "2021-09-10T18:00" }, { "id_employee": 1, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" }, { "id_employee": 3, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" }, { "id_employee": 4, - "time_slot": "2021-09-10T1900" + "time_slot": "2021-09-10T19:00" } ] } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/schemas/instance.json b/cornflow-dags/DAG/rostering/schemas/instance.json index 35c56cc5e..3b26878b2 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance.json +++ b/cornflow-dags/DAG/rostering/schemas/instance.json @@ -46,43 +46,91 @@ }, "requirements": { "type": "object", - "description": "Boolean values to activate or deactivate different requirements of the problem", + "description": "Parameters to activate or deactivate different requirements of the problem", "show": true, "filterable": false, "sortable": true, "properties": { + "rq02": { + "type": "string", + "title": "Weekly hours", + "description": "The employees weekly hours are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq03": { + "type": "string", + "title": "Max daily hours", + "description": "The employees maximum daily hours are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq05": { + "type": "string", + "title": "Work days", + "description": "The employees max numbers of days worked per week are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq06": { + "type": "string", + "title": "Min daily hours", + "description": "The employees minimum daily hours are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq07": { + "type": "string", + "title": "Rest hours", + "description": "The employees rest hours are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq08": { + "type": "string", + "title": "Managers", + "description": "A manager should be present into the store at all times", + "enum": ["strict", "soft", "deactivated"] + }, "rq09": { - "type": "boolean", + "type": "string", "title": "Skills", - "description": "The demand of skills has to be covered" + "description": "The demand of skills has to be covered", + "enum": ["strict", "soft", "deactivated"] }, "rq10": { - "type": "boolean", + "type": "string", "title": "Employee holidays", - "description": "The employee holidays are respected" + "description": "The employee holidays are respected", + "enum": ["strict", "soft", "deactivated"] }, "rq11": { - "type": "boolean", + "type": "string", "title": "Store holidays", - "description": "The days when a store is closed are respected" + "description": "The days when a store is closed are respected", + "enum": ["strict", "deactivated"] }, "rq12": { - "type": "boolean", + "type": "string", "title": "Employee downtime", - "description": "The employee downtime is respected" + "description": "The employee downtime is respected", + "enum": ["strict", "deactivated"] }, "rq13": { - "type": "boolean", + "type": "string", "title": "Employee starting hour preference", - "description": "The employee starting hour is respected" + "description": "The employee starting hour is respected", + "enum": ["strict", "soft", "deactivated"] }, "rq14": { - "type": "boolean", + "type": "string", "title": "Employee max hours worked", - "description": "The employee maximum hours worked preference is respected" + "description": "The employee maximum hours worked preference is respected", + "enum": ["strict", "soft", "deactivated"] } }, "required": [ + "rq02", + "rq03", + "rq05", + "rq06", + "rq07", + "rq08", "rq09", "rq10", "rq11", @@ -91,6 +139,66 @@ "rq14" ] }, + "penalties": { + "type": "object", + "description": "Parameters to activate or deactivate different requirements of the problem", + "show": true, + "filterable": false, + "sortable": true, + "properties": { + "rq02": { + "type": "integer", + "title": "Weekly hours", + "description": "The penalty when the employees weekly hours are not respected" + }, + "rq03": { + "type": "integer", + "title": "Max daily hours", + "description": "The penalty when the employees maximum daily hours are not respected" + }, + "rq05": { + "type": "integer", + "title": "Work days", + "description": "The penalty when the employees max numbers of days worked per week are not respected" + }, + "rq06": { + "type": "integer", + "title": "Min daily hours", + "description": "The penalty when the employees minimum daily hours are not respected" + }, + "rq07": { + "type": "integer", + "title": "Rest hours", + "description": "The penalty when the employees rest hours are not respected" + }, + "rq08": { + "type": "integer", + "title": "Managers", + "description": "The penalty when there is not a manager present into the store at all times" + }, + "rq09": { + "type": "integer", + "title": "Skills", + "description": "The penalty when skill demand is not covered" + }, + "rq10": { + "type": "integer", + "title": "Employee holidays", + "description": "The penalty when the employee holidays are not respected" + }, + "rq13": { + "type": "integer", + "title": "Employee starting hour preference", + "description": "The penalty when the employee starting hour is not respected" + }, + "rq14": { + "type": "integer", + "title": "Employee max hours worked", + "description": "The penalty when the employee maximum hours worked preference is not respected" + } + }, + "required": [] + }, "employees": { "type": "array", "description": "Table with the employee master information", diff --git a/cornflow-dags/DAG/rostering/schemas/instance_checks.json b/cornflow-dags/DAG/rostering/schemas/instance_checks.json index 75fa7e70e..7a73d1e36 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance_checks.json +++ b/cornflow-dags/DAG/rostering/schemas/instance_checks.json @@ -137,6 +137,23 @@ }, "required": ["week", "employee", "hour"] } + }, + "penalties": { + "type": "array", + "title": "Penalties", + "description": "Some soft constraints do not have a penalty defined. They will be assigned the default value 1.", + "is_warning": true, + "items": { + "type": "object", + "properties": { + "requirement": { + "type": "string", + "title": "Requirement", + "description": "The name of the requirement for which the penalty is not defined" + } + }, + "required": ["requirement"] + } } }, "required": [] diff --git a/cornflow-dags/DAG/rostering/schemas/solution_checks.json b/cornflow-dags/DAG/rostering/schemas/solution_checks.json index 949865f5e..abe3edb4b 100644 --- a/cornflow-dags/DAG/rostering/schemas/solution_checks.json +++ b/cornflow-dags/DAG/rostering/schemas/solution_checks.json @@ -111,6 +111,176 @@ "required": ["timeslot", "id_skill", "number_missing"], "additionalProperties": false } + }, + "days_worked_per_week": { + "type": "array", + "title": "Max work days", + "description": "Table containing the information about weeks when an employee works more days than their work days", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "week": { + "type": "integer", + "title": "Week", + "description": "The week of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + }, + "nb_days_worked": { + "type": "integer", + "title": "Nb days worked", + "description": "The number of days worked by the employee on that week." + }, + "max_days_week": { + "type": "integer", + "title": "Max days week", + "description": "The number of work days of the employee." + } + }, + "required": ["week", "id_employee", "nb_days_worked", "max_days_week"], + "additionalProperties": false + } + }, + "min_hours_worked_per_day": { + "type": "array", + "title": "Min hours worked", + "description": "Table containing information about the days when an employee works less than the minimum work day duration.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + }, + "nb_hours_worked": { + "type": "number", + "title": "Nb hours worked", + "description": "The number of hours worked by the employee on that day." + }, + "min_hours_day": { + "type": "integer", + "title": "Min hours day", + "description": "The minimum number of hours worked by the employee of the employee." + } + }, + "required": ["date", "id_employee", "nb_hours_worked", "min_hours_day"], + "additionalProperties": false + } + }, + "employee_holidays": { + "type": "array", + "title": "Employee holidays", + "description": "Table containing information about the dates when an employee is working while they should be on holidays.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + } + }, + "required": ["date", "id_employee"], + "additionalProperties": false + } + }, + "employee_downtime": { + "type": "array", + "title": "Employee downtime", + "description": "Table containing information about the dates when an employee is working while they are on downtime.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + } + }, + "required": ["date", "id_employee"], + "additionalProperties": false + } + } + }, + "start_hour_preference": { + "type": "array", + "title": "Preferences - start hour", + "description": "Table containing information about the employees preferences about their starting hours that are not respected.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + }, + "start_hour": { + "type": "string", + "title": "Start hour", + "description": "The start hour of the employee." + } + } + }, + "required": ["date", "id_employee", "start_hour"], + "additionalProperties": false + } + }, + "number_hours_preferences": { + "type": "array", + "title": "Preferences - number of hours", + "description": "Table containing information about the employees preferences about their number of hours that are not respected.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + }, + "number_hours_worked": { + "type": "number", + "title": "Number hours worked", + "description": "The number of hours worked by the employee on that day." + } + }, + "required": ["date", "id_employee", "number_hours_worked"], + "additionalProperties": false } }, "required": [], diff --git a/cornflow-dags/DAG/rostering/solvers/mip_model.py b/cornflow-dags/DAG/rostering/solvers/mip_model.py index b853c0857..fa3342867 100644 --- a/cornflow-dags/DAG/rostering/solvers/mip_model.py +++ b/cornflow-dags/DAG/rostering/solvers/mip_model.py @@ -36,6 +36,8 @@ def __init__(self, instance, solution=None): self.first_ts_day_employee = SuperDict() self.demand = SuperDict() self.ts_demand_employee_skill = SuperDict() + self.ts_employees_holidays = TupList() + self.ts_skill_demand = TupList() self.preference_starts_ts = SuperDict() self.preference_hours_employee = SuperDict() self.preference_slots = SuperDict() @@ -43,6 +45,16 @@ def __init__(self, instance, solution=None): # Variables self.works = SuperDict() self.starts = SuperDict() + self.unmet_skill_demand = SuperDict() + self.unmet_preference_start = SuperDict() + self.unmet_preference_hours = SuperDict() + self.unmet_manager_constraint = SuperDict() + self.unmet_rest_hours_constraint = SuperDict() + self.unmet_employee_holidays_constraint = SuperDict() + self.unmet_min_daily_hours_constraint = SuperDict() + self.unmet_max_weekly_work_days_constraint = SuperDict() + self.unmet_max_daily_hours_constraint = SuperDict() + self.unmet_weekly_hours_constraint = SuperDict() self.initialize() @@ -107,6 +119,10 @@ def initialize(self): self.ts_demand_employee_skill = self.instance.get_ts_demand_employees_skill( self.employee_ts_availability ) + self.ts_skill_demand = self.instance.get_ts_skill_demand( + self.ts_demand_employee_skill.keys_tl() + ) + self.ts_employees_holidays = self.instance.get_employee_time_slots_holidays() self.preference_starts_ts = self.instance.get_employee_preference_start_ts() self.preference_hours_employee = self.instance.get_employee_preference_hours() self.preference_slots = self.instance.get_employee_time_slots_preferences() @@ -132,11 +148,139 @@ def create_variables(self): self.starts = SuperDict(self.starts) + # RQ02 + self.unmet_weekly_hours_constraint = pl.LpVariable.dicts( + "unmet_weekly_hours_constraint", + self.max_working_ts_week.keys_l(), + lowBound=0, + cat=pl.LpContinuous, + ) + self.unmet_weekly_hours_constraint = SuperDict( + self.unmet_weekly_hours_constraint + ) + + # RQ03 + self.unmet_max_daily_hours_constraint = pl.LpVariable.dicts( + "unmet_max_daily_hours_constraint", + self.workable_ts_day.keys_l(), + lowBound=0, + cat=pl.LpContinuous, + ) + self.unmet_max_daily_hours_constraint = SuperDict( + self.unmet_max_daily_hours_constraint + ) + + # RQ05 + self.unmet_max_weekly_work_days_constraint = pl.LpVariable.dicts( + "unmet_max_weekly_work_days_constraint", + self.workable_ts_week.keys_l(), + lowBound=0, + cat=pl.LpContinuous, + ) + self.unmet_max_weekly_work_days_constraint = SuperDict( + self.unmet_max_weekly_work_days_constraint + ) + + # RQ06 + self.unmet_min_daily_hours_constraint = pl.LpVariable.dicts( + "unmet_min_daily_hour_constraint", + self.workable_ts_day.keys_l(), + lowBound=0, + cat=pl.LpContinuous, + ) + self.unmet_min_daily_hours_constraint = SuperDict( + self.unmet_min_daily_hours_constraint + ) + + # RQ07 + self.unmet_rest_hours_constraint = pl.LpVariable.dicts( + "unmet_rest_hours_constraint", + self.incompatible_ts_employee, + lowBound=0, + upBound=1, + cat=pl.LpContinuous, + ) + self.unmet_rest_hours_constraint = SuperDict(self.unmet_rest_hours_constraint) + + # RQ08 + self.unmet_manager_constraint = pl.LpVariable.dicts( + "unmet_manager_constraints", + self.ts_managers.keys_l(), + lowBound=0, + upBound=1, + cat=pl.LpContinuous, + ) + self.unmet_manager_constraint = SuperDict(self.unmet_manager_constraint) + + # RQ09 + self.unmet_skill_demand = pl.LpVariable.dicts( + "unmet_skill_demand", self.ts_skill_demand, lowBound=0, cat=pl.LpContinuous + ) + self.unmet_skill_demand = SuperDict(self.unmet_skill_demand) + + # RQ10 + self.unmet_employee_holidays_constraint = pl.LpVariable.dicts( + "unmet_employees_holidays_constraint", + self.ts_employees_holidays, + lowBound=0, + upBound=1, + cat=pl.LpContinuous, + ) + self.unmet_employee_holidays_constraint = SuperDict( + self.unmet_employee_holidays_constraint + ) + + # RQ13 + self.unmet_preference_start = pl.LpVariable.dicts( + "unmet_preference_start", + self.preference_starts_ts.keys_l(), + lowBound=0, + upBound=1, + cat=pl.LpContinuous, + ) + self.unmet_preference_start = SuperDict(self.unmet_preference_start) + + # RQ14 + self.unmet_preference_hours = pl.LpVariable.dicts( + "unmet_preference_hours", + self.preference_slots.keys_l(), + lowBound=0, + cat=pl.LpContinuous, + ) + self.unmet_preference_hours = SuperDict(self.unmet_preference_hours) + def create_constraints(self, model): # RQ00: objective function - minimize working hours + big_m = ( + sum( + len(self.ts_employees) * max(self.demand.values()) for _ in self.ts_open + ) + / 10 + ) model += pl.lpSum( pl.lpSum(self.works[ts, e] for e in self.ts_employees[ts]) * self.demand[ts] for ts in self.ts_open + ) - big_m * ( + self.instance.get_penalty("rq02") + * pl.lpSum(self.unmet_weekly_hours_constraint.values()) + + self.instance.get_penalty("rq03") + * pl.lpSum(self.unmet_max_daily_hours_constraint.values()) + + self.instance.get_penalty("rq05") + * pl.lpSum(self.unmet_max_weekly_work_days_constraint.values()) + + self.instance.get_penalty("rq06") + * pl.lpSum(self.unmet_min_daily_hours_constraint.values()) + + self.instance.get_penalty("rq07") + * pl.lpSum(self.unmet_rest_hours_constraint.values()) + + self.instance.get_penalty("rq08") + * pl.lpSum(self.unmet_manager_constraint.values()) + + self.instance.get_penalty("rq09") + * pl.lpSum(self.unmet_skill_demand.values()) + + self.instance.get_penalty("rq10") + * pl.lpSum(self.unmet_employee_holidays_constraint.values()) + + self.instance.get_penalty("rq13") + * pl.lpSum(self.unmet_preference_start.values()) + + self.instance.get_penalty("rq14") + * pl.lpSum(self.unmet_preference_hours.values()) ) # RQ01: at least one employee at all times @@ -144,18 +288,24 @@ def create_constraints(self, model): model += pl.lpSum(self.works[ts, e] for e in _employees) >= 1 # RQ02: employees work their weekly hours - for (w, e), max_slots in self.max_working_ts_week.items(): - model += ( - pl.lpSum(self.works[ts, e] for ts in self.workable_ts_week[w, e]) - == max_slots - ) + if self.instance.get_requirement("rq02") != "deactivated": + for (w, e), max_slots in self.max_working_ts_week.items(): + model += ( + pl.lpSum(self.works[ts, e] for ts in self.workable_ts_week[w, e]) + - (self.instance.get_requirement("rq02") == "soft") + * self.unmet_weekly_hours_constraint[w, e] + == max_slots + ) # RQ03: employees can not exceed their daily hours - for (d, e), slots in self.workable_ts_day.items(): - model += ( - pl.lpSum(self.works[ts, e] for ts in slots) - <= self.max_working_ts_day[d, e] - ) + if self.instance.get_requirement("rq03") != "deactivated": + for (d, e), slots in self.workable_ts_day.items(): + model += ( + pl.lpSum(self.works[ts, e] for ts in slots) + - (self.instance.get_requirement("rq03") == "soft") + * self.unmet_max_daily_hours_constraint[d, e] + <= self.max_working_ts_day[d, e] + ) # RQ04A: starts if does not work in one ts but in the next it does for ts, ts2, e in self.ts_ts_employee: @@ -170,47 +320,87 @@ def create_constraints(self, model): model += pl.lpSum(self.starts[ts, e] for ts in slots) <= 1 # RQ05: max days worked per week - for (w, e), slots in self.workable_ts_week.items(): - model += ( - pl.lpSum(self.starts[ts, e] for ts in slots) - <= self.max_working_days[w, e] - ) + if self.instance.get_requirement("rq05") != "deactivated": + for (w, e), slots in self.workable_ts_week.items(): + model += ( + pl.lpSum(self.starts[ts, e] for ts in slots) + - (self.instance.get_requirement("rq05") == "soft") + * self.unmet_max_weekly_work_days_constraint[w, e] + <= self.max_working_days[w, e] + ) # RQ06: employees at least work the minimum hours - for (d, e), slots in self.workable_ts_day.items(): - model += pl.lpSum( - self.works[ts, e] for ts in slots - ) >= self.min_working_ts_day[d, e] * pl.lpSum( - self.starts[ts, e] for ts in slots - ) + if self.instance.get_requirement("rq06") != "deactivated": + for (d, e), slots in self.workable_ts_day.items(): + model += pl.lpSum(self.works[ts, e] for ts in slots) + ( + self.instance.get_requirement("rq06") == "soft" + ) * self.unmet_min_daily_hours_constraint[ + d, e + ] >= self.min_working_ts_day[ + d, e + ] * pl.lpSum( + self.starts[ts, e] for ts in slots + ) # RQ07: employees at least have to rest an amount of hours between working days. - for ts, ts2, e in self.incompatible_ts_employee: - model += self.works[ts, e] + self.works[ts2, e] <= 1 + if self.instance.get_requirement("rq07") != "deactivated": + for ts, ts2, e in self.incompatible_ts_employee: + model += ( + self.works[ts, e] + + self.works[ts2, e] + - (self.instance.get_requirement("rq07") == "soft") + * self.unmet_rest_hours_constraint[ts, ts2, e] + <= 1 + ) # RQ08: a manager has to be working at all times - for ts, _employees in self.ts_managers.items(): - model += pl.lpSum(self.works[ts, e] for e in _employees) >= 1 + if self.instance.get_requirement("rq08") != "deactivated": + for ts, _employees in self.ts_managers.items(): + model += ( + pl.lpSum(self.works[ts, e] for e in _employees) + + (self.instance.get_requirement("rq08") == "soft") + * self.unmet_manager_constraint[ts] + >= 1 + ) # RQ09: The demand for each skill is covered - if self.instance.get_requirement("rq09"): + if self.instance.get_requirement("rq09") != "deactivated": for ( ts, id_skill, skill_demand, ), employees in self.ts_demand_employee_skill.items(): - model += pl.lpSum(self.works[ts, e] for e in employees) >= skill_demand + model += ( + pl.lpSum(self.works[ts, e] for e in employees) + + (self.instance.get_requirement("rq09") == "soft") + * self.unmet_skill_demand[ts, id_skill] + >= skill_demand + ) + + # RQ10: Employee holidays + if self.instance.get_requirement("rq10") == "soft": + for ts, e in self.ts_employees_holidays: + model += ( + self.works[ts, e] <= self.unmet_employee_holidays_constraint[ts, e] + ) # RQ13: Starting hour preference - if self.instance.get_requirement("rq13"): + if self.instance.get_requirement("rq13") != "deactivated": for (d, e), slots in self.preference_starts_ts.items(): - model += pl.lpSum(self.starts[ts, e] for ts in slots) == 1 + model += ( + pl.lpSum(self.starts[ts, e] for ts in slots) + + (self.instance.get_requirement("rq13") == "soft") + * self.unmet_preference_start[d, e] + == 1 + ) # RQ14: max preference hours - if self.instance.get_requirement("rq14"): + if self.instance.get_requirement("rq14") != "deactivated": for (d, e), slots in self.preference_slots.items(): model += ( pl.lpSum(self.works[ts, e] for ts in slots) + - (self.instance.get_requirement("rq14") == "soft") + * self.unmet_preference_hours[d, e] <= self.preference_hours_employee[d, e] ) diff --git a/libs/client/cornflow_client/core/instance_solution.py b/libs/client/cornflow_client/core/instance_solution.py index 3659b77b9..f856606cb 100644 --- a/libs/client/cornflow_client/core/instance_solution.py +++ b/libs/client/cornflow_client/core/instance_solution.py @@ -366,7 +366,7 @@ def get_week_from_date_string(string: str) -> int: @staticmethod def get_week_from_datetime_string(string: str) -> int: """Returns the integer value of the week for the given string""" - datetime_object = datetime.strptime(string, "%Y-%m-%dT%H:%M:%S") + datetime_object = datetime.strptime(string, "%Y-%m-%dT%H:%M") return datetime_object.isocalendar()[1] @staticmethod diff --git a/libs/client/cornflow_client/tests/unit/test_instance_solution_methods.py b/libs/client/cornflow_client/tests/unit/test_instance_solution_methods.py index 1ab096b99..36123cca4 100644 --- a/libs/client/cornflow_client/tests/unit/test_instance_solution_methods.py +++ b/libs/client/cornflow_client/tests/unit/test_instance_solution_methods.py @@ -278,7 +278,7 @@ def test_get_week_from_date_string(self): self.assertEqual(result, expected) def test_get_week_from_datetime_string(self): - string = "2022-01-01T12:00:00" + string = "2022-01-01T12:00" result = InstanceSolutionCore.get_week_from_datetime_string(string) expected = 52 self.assertEqual(result, expected) From e59c04de9dbef75d1d72d57d26426d26164f1e18 Mon Sep 17 00:00:00 2001 From: marioncottard <86973971+marioncottard@users.noreply.github.com> Date: Wed, 4 Oct 2023 20:50:10 +0200 Subject: [PATCH 05/22] Feature/rostering employee work days + check for missing data (#465) * Changed all hours from int to string * Soft constraints * Deleted methods that are in InstanceSolutionCore * Added output checks, Applied formatter * Employee work days * Added check for missing input data * Cleaning * Updated readme * Updated readme * Cleaning * Docstrings * Feature/rostering fix worktable (#466) * Fixed schedules * Added output data checks, updated readme * Cleaning * Added input data checks for fixed worktable hours --------- Co-authored-by: Guillermo Gonzalez-Santander --- cornflow-dags/DAG/rostering/README.rst | 6 + cornflow-dags/DAG/rostering/core/const.py | 14 +- .../DAG/rostering/core/experiment.py | 25 +++ cornflow-dags/DAG/rostering/core/instance.py | 162 ++++++++++++++++-- cornflow-dags/DAG/rostering/core/solution.py | 2 +- cornflow-dags/DAG/rostering/core/tools.py | 2 +- .../DAG/rostering/data/test_instance_1.json | 34 +++- .../DAG/rostering/data/test_instance_2.json | 8 +- .../DAG/rostering/data/test_instance_3.json | 8 +- .../DAG/rostering/data/test_instance_4.json | 8 +- .../DAG/rostering/data/test_instance_5.json | 8 +- .../DAG/rostering/data/test_instance_6.json | 12 +- .../DAG/rostering/data/test_instance_7.json | 8 +- .../DAG/rostering/data/test_instance_8.json | 15 +- .../DAG/rostering/schemas/instance.json | 93 +++++++++- .../rostering/schemas/instance_checks.json | 52 ++++++ .../rostering/schemas/solution_checks.json | 56 ++++++ .../DAG/rostering/solvers/mip_model.py | 47 +++++ 18 files changed, 518 insertions(+), 42 deletions(-) diff --git a/cornflow-dags/DAG/rostering/README.rst b/cornflow-dags/DAG/rostering/README.rst index 63bf07bc0..e53d0557e 100644 --- a/cornflow-dags/DAG/rostering/README.rst +++ b/cornflow-dags/DAG/rostering/README.rst @@ -24,6 +24,8 @@ This decision is subject to: - RQ12: employees can not work during downtime. - RQ13: employee starting hour preference. - RQ14: employee max preference hours. +- RQ15: employee weekly schedule +- RQ16: fixed worktable Parameters ---------- @@ -38,6 +40,8 @@ Parameters - Employee preferences: starting and number of hours preferences for one day. - Weekly schedule: starting and ending hours for each week day. - Schedule exceptions: starting and ending hours for a specific date. +- Employee schedule: days of the week the employee can work on +- Fixed worktable: worktable fixed by the user - Parameters: @@ -61,5 +65,7 @@ Parameters - rq12: "strict" or "deactivated for the employee downtime constraint - rq13: "soft", "strict" or "deactivated for the employee start hour preferences constraint - rq14: "soft", "strict" or "deactivated for the employee max preference hours constraint + - rq15: "soft", "strict" or "deactivated for the employee schedule constraint + - rq16: "soft", "strict" or "deactivated for the fixed worktable constraint - Penalties: table indicating for each soft constraint the penalty level when it is not respected. \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/core/const.py b/cornflow-dags/DAG/rostering/core/const.py index 81ea3f674..756c548da 100644 --- a/cornflow-dags/DAG/rostering/core/const.py +++ b/cornflow-dags/DAG/rostering/core/const.py @@ -1,11 +1,15 @@ INSTANCE_KEYS_RELATION = { ("employees", "id"): [ - ("contracts", "id_employee"), - ("skills_employees", "id_employee"), + ("contracts", "id_employee", True), + ("skills_employees", "id_employee", False), + ("employee_holidays", "id_employee", False), + ("employee_downtime", "id_employee", False), + ("employee_preferences", "id_employee", False), + ("employee_schedule", "id_employee", False), ], - ("shifts", "id"): [("contracts", "id_shift")], + ("shifts", "id"): [("contracts", "id_shift", False)], ("skills", "id"): [ - ("skills_employees", "id_skill"), - ("skill_demand", "id_skill"), + ("skills_employees", "id_skill", False), + ("skill_demand", "id_skill", False), ], } diff --git a/cornflow-dags/DAG/rostering/core/experiment.py b/cornflow-dags/DAG/rostering/core/experiment.py index 624e272d9..80111a4ad 100644 --- a/cornflow-dags/DAG/rostering/core/experiment.py +++ b/cornflow-dags/DAG/rostering/core/experiment.py @@ -49,6 +49,8 @@ def check_solution(self, *args, **kwargs) -> dict: employee_downtime=self.check_employees_downtime(), start_hour_preference=self.check_start_hour_preference(), number_hours_preferences=self.check_number_hours_preference(), + employee_work_days=self.check_employee_work_days(), + fixed_worktable=self.check_fixed_worktable() ).vfilter(lambda v: len(v)) def get_objective(self) -> float: @@ -261,6 +263,29 @@ def check_number_hours_preference(self): ) ) + def check_employee_work_days(self) -> TupList: + """Checks if some employees are assigned to work on their days off""" + work_days = self.instance.get_employee_time_slots_rest_days().take([1, 2]) + return ( + self.solution.get_ts_employee() + .to_tuplist() + .vapply_col(0, lambda v: v[0][:10]) + .intersect(work_days) + .vapply( + lambda v: {"date": v[0], "id_employee": v[1]} + ) + ) + + def check_fixed_worktable(self) -> TupList: + """ Checks if some parts of the fixed worktable are not respected """ + ts_employee = self.solution.get_ts_employee().to_tuplist() + + return( + self.instance.get_fixed_worktable() + .vfilter(lambda v: v not in ts_employee) + .vapply(lambda v: {"time_slot": v[0], "id_employee": v[1]}) + ) + def get_one_employee_percentage(self) -> float: """Returns the percentage of time slots where only one employee is working""" ts_employee = self.solution.get_ts_employee() diff --git a/cornflow-dags/DAG/rostering/core/instance.py b/cornflow-dags/DAG/rostering/core/instance.py index d3cb1591a..296c90a1b 100644 --- a/cornflow-dags/DAG/rostering/core/instance.py +++ b/cornflow-dags/DAG/rostering/core/instance.py @@ -1,19 +1,17 @@ """ """ -import os -import pickle - # Imports from libraries from datetime import datetime, timedelta -from math import ceil +import os +import pickle +from pytups import SuperDict, TupList from typing import Dict, Tuple +from math import ceil # Imports from cornflow libraries from cornflow_client import InstanceCore from cornflow_client.core.tools import load_json -from pytups import SuperDict, TupList - from .const import INSTANCE_KEYS_RELATION # Imports from internal modules @@ -124,6 +122,21 @@ def from_dict(cls, data: dict) -> "Instance": else: data_p["employee_preferences"] = SuperDict({}) + if data.get("employee_schedule"): + data_p["employee_schedule"] = TupList( + data["employee_schedule"] + ).to_dict(result_col="week_day", indices=["id_employee", "id_contract"]) + else: + data_p["employee_schedule"] = SuperDict() + + if data.get("fixed_worktables"): + data_p["fixed_worktables"] = { + (el["id_employee"], el["date"], el["hour"]): el + for el in data["fixed_worktables"] + } + else: + data_p["fixed_worktables"] = SuperDict({}) + return cls(data_p) def to_dict(self) -> Dict: @@ -138,6 +151,7 @@ def to_dict(self) -> Dict: "employee_downtime", "store_holidays", "employee_preferences", + "fixed_worktables" ] data_p = {el: self.data[el].values_l() for el in tables} @@ -178,6 +192,11 @@ def to_dict(self) -> Dict: dict(id_employee=id_employee, day=day, hours=hours, start=start) for (id_employee, day, hours, start) in self.data["employee_preferences"] ] + data_p["employee_schedule"] = [ + dict(id_employee=id_employee, week_day=week_day, id_contract=id_contract) + for (id_employee, id_contract), weekdays in self.data["employee_schedule"].items() + for week_day in weekdays + ] return pickle.loads(pickle.dumps(data_p, -1)) def cache_properties(self): @@ -193,6 +212,7 @@ def cache_properties(self): def check(self) -> dict: return SuperDict( incoherent_foreign_keys=self.check_indexes_coherence(), + missing_data=self.check_missing_data(), timeslot_length=self.check_timeslot_length(), penalties=self.check_penalties(), **self.check_timeslot_coherence(), @@ -201,7 +221,7 @@ def check(self) -> dict: def check_indexes_coherence(self) -> list: errors = list() for pk, fk_list in INSTANCE_KEYS_RELATION.items(): - for fk_table, fk_column in fk_list: + for fk_table, fk_column, _ in fk_list: fk_values = self._get_property(fk_table, fk_column).values_tl() for fk in fk_values: if fk not in self._get_property(pk[0], pk[1]).values_tl(): @@ -216,18 +236,36 @@ def check_indexes_coherence(self) -> list: return errors + def check_missing_data(self) -> list: + errors = list() + for pk, fk_list in INSTANCE_KEYS_RELATION.items(): + for fk_table, fk_column, f_item_required in fk_list: + if not f_item_required: + continue + items = self._get_property(pk[0], pk[1]).values_tl() + fk_items = self._get_property(fk_table, fk_column).values_tl() + errors += items.vfilter(lambda v: v not in fk_items).vapply(lambda v: { + "primary_table": pk[0], + "foreign_table": fk_table, + "key": pk[1], + "value": v, + }) + + return errors + def check_timeslot_length(self): slot_length = self._get_slot_length() if slot_length not in [15, 30, 60]: return dict(timeslot_length=slot_length) return dict() - def check_timeslot_coherence(self): + def check_timeslot_coherence(self) -> dict: checks = SuperDict( weekly_schedule_timeslots=TupList(), schedule_exceptions_timeslots=TupList(), shift_hours_timeslots=TupList(), employee_preferences_timeslots=TupList(), + fixed_worktable_timeslots=TupList() ) slot_length = self._get_slot_length() weekly_schedule = self._get_weekly_schedule(round_ts=False) @@ -236,7 +274,8 @@ def check_timeslot_coherence(self): round_ts=False ) contract_end_hours = self._get_employees_contract_ending_hour(round_ts=False) - employee_preferences = self._get_employee_preferences() + employee_preferences = self._get_employee_preferences(round_ts=False) + fixed_worktable = self.get_fixed_worktable(round_ts=False) for key, values in weekly_schedule.items(): checks["weekly_schedule_timeslots"] += TupList( @@ -288,6 +327,12 @@ def check_timeslot_coherence(self): if int(hour_string[3:]) % slot_length != 0 ) + checks["fixed_worktable_timeslots"] = TupList( + {"date": ts[:10], "employee": employee, "hour": ts[-5:]} + for (ts, employee) in fixed_worktable + if int(ts[-2:]) % slot_length != 0 + ) + return checks.vfilter(lambda v: len(v)) def check_penalties(self): @@ -498,9 +543,7 @@ def round_hour_string_up_to_tuple(self, hour_string): if rounded_hour != 23 and rounded_minutes == 60: return rounded_hour + 1, 0 elif rounded_hour == 23 and rounded_minutes == 60: - return 24, 0 - elif rounded_hour == 0 and rounded_minutes == 0: - return 24, 0 + return 0, 0 return rounded_hour, rounded_minutes def _format_hour_tuples(self, tup, round_ts): @@ -538,6 +581,33 @@ def _round_hour_string_up(self, hour_string): hour, minutes = self.round_hour_string_up_to_tuple(hour_string) return get_hour_string_from_hour_minute(hour, minutes) + def _get_employee_schedule(self, set_default=True, model=False) -> SuperDict: + """ + Returns a SuperDict with the week and employee as key and the + worked weekdays as values. + By default, an employee can work any day. + For example: [(12, 1), (12, 3), ...] + """ + employees_contracts = self._get_employees_contracts() + employee_schedule = ( + self.data["employee_schedule"] + .to_tuplist() + .to_dict(result_col=2, indices=[0, 1]) + ) + if not set_default: + return ( + employees_contracts + .kvapply(lambda k, v: employee_schedule.get((k[1], v), None)) + .vfilter(lambda v: v) + ) + if self.get_requirement("rq15") == "strict" or (self.get_requirement("rq15") == "soft" and model): + return ( + employees_contracts + .kvapply(lambda k, v: employee_schedule.get((k[1], v), list(range(7)))) + ) + else: + return employees_contracts.vapply(lambda v: list(range(7))) + def _get_start_date(self) -> datetime: """Returns the datetime object of the starting date""" return self.get_date_from_string(self.data["parameters"]["starting_date"]) @@ -681,8 +751,11 @@ def _get_employees_contract_starting_hour(self, round_ts=True) -> SuperDict: """ start = self._get_shifts("start") + ts_length = self._get_slot_length() if round_ts: - start = start.vapply(self._round_hour_string_down) + start = start.vapply( + lambda v: v[:3] + str(ts_length * (int(v[3:]) // ts_length)).zfill(2) + ) return self._get_employees_contract_shift().vapply(lambda s: start[s]) @@ -696,9 +769,14 @@ def _get_employees_contract_ending_hour( For example: {(36, 1): 21, ...} """ end = self._get_shifts("end") + ts_length = self._get_slot_length() if round_ts: - end = end.vapply(self._round_hour_string_up) + end = end.vapply( + lambda v: self._round_hour_string_up( + v[:3] + str(ts_length * ceil(int(v[3:]) / ts_length)).zfill(2) + ) + ) return self._get_employees_contract_shift().vapply(lambda s: end[s]) def _get_employee_time_slots_week(self) -> TupList: @@ -726,6 +804,7 @@ def _get_employee_time_slots_week(self) -> TupList: and (e, self._get_date_string_from_ts(ts)) not in self._get_employee_downtime() if self._get_date_string_from_ts(ts) not in self._get_store_holidays() + if ts.isoweekday() in self._get_employee_schedule()[w, e] ) def get_employees_time_slots_week(self) -> SuperDict: @@ -769,8 +848,43 @@ def get_employee_time_slots_holidays(self) -> TupList: and (e, self._get_date_string_from_ts(ts)) not in self._get_employee_downtime() if self._get_date_string_from_ts(ts) not in self._get_store_holidays() + if ts.isoweekday() in self._get_employee_schedule()[w, e] + ) + + def get_employee_time_slots_rest_days(self) -> TupList: + """ + Returns a TupList with the combinations of employees, days and time slots + in which the employees doesn't work. + For example: [("2021-09-06T07:00", "2021-09-06", 1), + ("2021-09-06T08:00", "2021-09-06", 1), ...] + """ + start = ( + self._get_employees_contract_starting_hour() + .vapply(lambda v: self._get_hour_from_hour_string(v)) + ) + end = ( + self._get_employees_contract_ending_hour() + .vapply(lambda v: self._get_hour_from_hour_string(v)) ) + return TupList( + (self.get_time_slot_string(ts), self._get_date_string_from_ts(ts), e) + for ts in self.time_slots + for (w, e) in start + if self._get_week_from_ts(ts) == w + and start[w, e] <= self._get_hour_from_ts(ts) < end[w, e] + and (e, self._get_date_string_from_ts(ts)) + not in self._get_employee_holidays() + and (e, self._get_date_string_from_ts(ts)) + not in self._get_employee_downtime() + if self._get_date_string_from_ts(ts) not in self._get_store_holidays() + if ts.isoweekday() not in self._get_employee_schedule(model=True)[w, e] + ) + + @staticmethod + def get_employees_rest_days(ts_employees_rest_days): + return ts_employees_rest_days.take([1, 2]).unique2().vapply(lambda v: tuple(v)) + def get_consecutive_time_slots_employee(self) -> TupList: """ Returns a TupList with a time slot, the nex time slot in the same day @@ -1173,6 +1287,16 @@ def _get_employee_preferences(self, round_ts=True) -> TupList: lambda v: self._round_hour_string_up(v[3]) if round_ts else v[3], ) + def get_fixed_worktable(self, round_ts=True) -> TupList: + """ + Returns a TupList with the fixed schedule + For example: [("2021-09-06T08:00", 1), ("2021-09-06T09:00", 1) ...] + """ + return TupList(self.data["fixed_worktables"].keys_tl()).vapply_col( + None, + lambda v: v[1] + "T" + self._round_hour_string_down(v[2]) if round_ts else v[2], + ).take([3, 0]) + def get_employee_time_slots_preferences(self) -> SuperDict: """ Returns a SuperDict with the date and employee tuple as key @@ -1213,6 +1337,16 @@ def get_employee_preference_start_ts(self) -> SuperDict: return starts_ts.to_dict(0) + def get_employee_fixed_worktable(self) -> TupList: + """ + Returns a TupList with the employees and the timeslots they have to work on + For example: [("2021-09-06T08:00", 1), ("2021-09-06T09:00", 1) ...] + """ + availability = self.get_employees_ts_availability() + fixed_worktable = self.get_fixed_worktable() + + return fixed_worktable.vfilter(lambda v: v in availability) + def get_employee_preference_hours(self) -> SuperDict: """ Returns a SuperDict with the date and employee tuple as key diff --git a/cornflow-dags/DAG/rostering/core/solution.py b/cornflow-dags/DAG/rostering/core/solution.py index 2a281cf05..ad4f3a7af 100644 --- a/cornflow-dags/DAG/rostering/core/solution.py +++ b/cornflow-dags/DAG/rostering/core/solution.py @@ -4,11 +4,11 @@ # Imports from libraries import os import pickle +from pytups import SuperDict, TupList # Imports from cornflow libraries from cornflow_client import SolutionCore from cornflow_client.core.tools import load_json -from pytups import SuperDict, TupList class Solution(SolutionCore): diff --git a/cornflow-dags/DAG/rostering/core/tools.py b/cornflow-dags/DAG/rostering/core/tools.py index 22f6afcfb..625cb4a75 100644 --- a/cornflow-dags/DAG/rostering/core/tools.py +++ b/cornflow-dags/DAG/rostering/core/tools.py @@ -8,7 +8,7 @@ def get_hour_string_from_date_time(ts: datetime) -> str: def get_hour_string_from_hour_minute(hour: int, minute: int) -> str: """Returns the hour string for the given time slot""" - return str(hour).zfill(2) + ":" + str(minute).zfill(2) + return datetime.now().replace(hour=hour, minute=minute).strftime("%H:%M") def get_one_date(starting_date: datetime, weeks: int = 0, days: int = 0) -> datetime: diff --git a/cornflow-dags/DAG/rostering/data/test_instance_1.json b/cornflow-dags/DAG/rostering/data/test_instance_1.json index b3e3f3231..adfd64353 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_1.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_1.json @@ -48,8 +48,8 @@ "id_shift": 3, "start_contract": "2021-09-06", "end_contract": null, - "weekly_hours": 40, - "days_worked": 5 + "weekly_hours": 32, + "days_worked": 4 }, { "id": 12, @@ -434,6 +434,28 @@ "ending_hour": "20:00" } ], + "employee_schedule": [ + { + "id_employee": 1, + "id_contract": 11, + "week_day": 1 + }, + { + "id_employee": 1, + "id_contract": 11, + "week_day": 2 + }, + { + "id_employee": 1, + "id_contract": 11, + "week_day": 3 + }, + { + "id_employee": 1, + "id_contract": 11, + "week_day": 5 + } + ], "parameters": { "horizon": 1, "slot_length": 60, @@ -453,7 +475,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "soft", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -465,6 +489,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_2.json b/cornflow-dags/DAG/rostering/data/test_instance_2.json index 748092b54..c31eeef68 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_2.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_2.json @@ -456,7 +456,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -468,6 +470,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_3.json b/cornflow-dags/DAG/rostering/data/test_instance_3.json index d879f8927..c87d2b1a9 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_3.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_3.json @@ -470,7 +470,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -482,6 +484,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_4.json b/cornflow-dags/DAG/rostering/data/test_instance_4.json index 0f5c75fa7..8ce86da33 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_4.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_4.json @@ -497,7 +497,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -509,6 +511,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_5.json b/cornflow-dags/DAG/rostering/data/test_instance_5.json index 8dbeae129..30f01cce0 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_5.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_5.json @@ -464,7 +464,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -476,6 +478,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_6.json b/cornflow-dags/DAG/rostering/data/test_instance_6.json index c45f4cd13..bb85137a2 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_6.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_6.json @@ -22780,13 +22780,15 @@ "rq05": "strict", "rq06": "strict", "rq07": "strict", - "rq08": "strict", - "rq09": "deactivated", + "rq08": "soft", + "rq09": "strict", "rq10": "strict", "rq11": "strict", "rq12": "strict", "rq13": "deactivated", - "rq14": "deactivated" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -22798,6 +22800,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_7.json b/cornflow-dags/DAG/rostering/data/test_instance_7.json index b900b8fff..a71e4bccd 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_7.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_7.json @@ -4145,7 +4145,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 1, @@ -4157,6 +4159,8 @@ "rq09": 2, "rq10": 1, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 1, + "rq16": 5 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/data/test_instance_8.json b/cornflow-dags/DAG/rostering/data/test_instance_8.json index a8989894f..e5dabbd15 100644 --- a/cornflow-dags/DAG/rostering/data/test_instance_8.json +++ b/cornflow-dags/DAG/rostering/data/test_instance_8.json @@ -4126,6 +4126,13 @@ "start": "08:00" } ], + "fixed_worktables": [ + { + "id_employee": 1, + "date": "2021-09-06", + "hour": "18:00" + } + ], "employee_holidays": [ { "id_employee": 1, @@ -4165,7 +4172,9 @@ "rq11": "strict", "rq12": "strict", "rq13": "soft", - "rq14": "soft" + "rq14": "soft", + "rq15": "strict", + "rq16": "strict" }, "penalties": { "rq02": 4, @@ -4177,6 +4186,8 @@ "rq09": 1, "rq10": 5, "rq13": 1, - "rq14": 1 + "rq14": 1, + "rq15": 5, + "rq16": 2 } } \ No newline at end of file diff --git a/cornflow-dags/DAG/rostering/schemas/instance.json b/cornflow-dags/DAG/rostering/schemas/instance.json index 3b26878b2..24806b4f1 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance.json +++ b/cornflow-dags/DAG/rostering/schemas/instance.json @@ -122,6 +122,18 @@ "title": "Employee max hours worked", "description": "The employee maximum hours worked preference is respected", "enum": ["strict", "soft", "deactivated"] + }, + "rq15": { + "type": "string", + "title": "Employee work days", + "description": "The employee work days are respected", + "enum": ["strict", "soft", "deactivated"] + }, + "rq16": { + "type": "string", + "title": "Fixed worktable", + "description": "The employees fixed work table is respected", + "enum": ["strict", "soft", "deactivated"] } }, "required": [ @@ -136,7 +148,9 @@ "rq11", "rq12", "rq13", - "rq14" + "rq14", + "rq15", + "rq16" ] }, "penalties": { @@ -195,6 +209,16 @@ "type": "integer", "title": "Employee max hours worked", "description": "The penalty when the employee maximum hours worked preference is not respected" + }, + "rq15": { + "type": "integer", + "title": "Employee work days", + "description": "The penalty when the employee work days are not respected" + }, + "rq16": { + "type": "integer", + "title": "Fixed worktable", + "description": "The penalty when the employees fixed work table is respected" } }, "required": [] @@ -705,6 +729,73 @@ } } } + }, + "employee_schedule": { + "type": "array", + "title": "Employees schedules", + "description": "Table with the week days worked by the employees. If an employee isn't in the table, it will be assumed that they can work every day of the week.", + "show": true, + "filterable": true, + "sortable": true, + "items": { + "type": "object", + "properties": { + "id_employee": { + "description": "The unique identifier of the employee", + "title": "Employee id.", + "type": "integer", + "sortable": true, + "filterable": true + }, + "week_day": { + "description": "Day of the week in number. 1 is Monday", + "title": "Day of week", + "type": "number", + "$comment": "Day. Monday 1", + "sortable": true, + "filterable": true + } + }, + "required": ["id_employee", "week_day"] + } + }, + "fixed_worktables": { + "type": "array", + "description": "Table with the fixed worktables indicating for each employee in which time slots they have to work", + "show": true, + "filterable": true, + "sortable": true, + "items": { + "type": "object", + "properties": { + "id_employee": { + "type": "integer", + "description": "The unique identifier for each employee.", + "title": "Employee id.", + "sortable": true, + "filterable": true + }, + "date": { + "type": "string", + "title": "Date", + "description": "The date the employee has to work on", + "sortable": true, + "filterable": true + }, + "hour": { + "title": "Hour", + "type": "string", + "description": "The hour the employee has to work on.", + "sortable": true, + "filterable": true + } + }, + "required": [ + "id_employee", + "date", + "hour" + ] + } } }, "required": [ diff --git a/cornflow-dags/DAG/rostering/schemas/instance_checks.json b/cornflow-dags/DAG/rostering/schemas/instance_checks.json index 7a73d1e36..9d8bf8c41 100644 --- a/cornflow-dags/DAG/rostering/schemas/instance_checks.json +++ b/cornflow-dags/DAG/rostering/schemas/instance_checks.json @@ -26,6 +26,31 @@ "additionalProperties": false } }, + "missing_data": { + "type": "array", + "title": "Missing data", + "description": "Table containing the data about missing input data. The entry with {key}={value} from table {primary_table} does not have an associated entry in {foreign_table}.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "primary_table": { + "type": "string" + }, + "foreign_table": { + "type": "string" + }, + "key": { + "type": "string" + }, + "value": { + "type": ["integer", "string"] + } + }, + "required": ["primary_table", "foreign_table", "key", "value"], + "additionalProperties": false + } + }, "timeslot_length": { "type": "object", "title": "Timeslot length", @@ -138,6 +163,33 @@ "required": ["week", "employee", "hour"] } }, + "fixed_worktable_timeslots": { + "type": "array", + "title": "Fixed worktable timeslots", + "is_warning": true, + "description": "The hours provided in the fixed worktable table are not coherent with the timeslot length. The hours will be rounded to match timeslot length.", + "items": { + "type": "object", + "properties": { + "week": { + "type": "integer", + "title": "Week", + "description": "The week of the problem" + }, + "employee": { + "type": "integer", + "title": "Employee", + "description": "The employee with the problem" + }, + "hour": { + "type": "string", + "title": "Hour", + "description": "The hour of the incoherence" + } + }, + "required": ["week", "employee", "hour"] + } + }, "penalties": { "type": "array", "title": "Penalties", diff --git a/cornflow-dags/DAG/rostering/schemas/solution_checks.json b/cornflow-dags/DAG/rostering/schemas/solution_checks.json index abe3edb4b..983d65fd1 100644 --- a/cornflow-dags/DAG/rostering/schemas/solution_checks.json +++ b/cornflow-dags/DAG/rostering/schemas/solution_checks.json @@ -281,6 +281,62 @@ }, "required": ["date", "id_employee", "number_hours_worked"], "additionalProperties": false + }, + "employee_work_days": { + "type": "array", + "title": "Employee work days", + "description": "Table containing the information about dates when the employees work days are not respected.", + "is_warning": false, + "items": { + "type": "object", + "properties": { + "date": { + "type": "string", + "title": "Date", + "description": "The date of the issue." + }, + "id_employee": { + "type": "integer", + "title": "Id employee", + "description": "The unique identifier of the employee." + } + }, + "required": [ + "date", + "id_employee" + ], + "additionalProperties": false + } + }, + "fixed_worktable": { + "type": "array", + "description": "Table containing information about the parts of the fixed worktable that are not respected.", + "show": true, + "filterable": true, + "sortable": true, + "items": { + "type": "object", + "properties": { + "id_employee": { + "type": "integer", + "description": "The unique identifier for each employee.", + "title": "Employee id.", + "sortable": true, + "filterable": true + }, + "time_slot": { + "type": "string", + "title": "Time slot", + "description": "The time slot the employee should be working on", + "sortable": true, + "filterable": true + } + }, + "required": [ + "id_employee", + "time_slot" + ] + } } }, "required": [], diff --git a/cornflow-dags/DAG/rostering/solvers/mip_model.py b/cornflow-dags/DAG/rostering/solvers/mip_model.py index fa3342867..05d90458c 100644 --- a/cornflow-dags/DAG/rostering/solvers/mip_model.py +++ b/cornflow-dags/DAG/rostering/solvers/mip_model.py @@ -37,10 +37,13 @@ def __init__(self, instance, solution=None): self.demand = SuperDict() self.ts_demand_employee_skill = SuperDict() self.ts_employees_holidays = TupList() + self.ts_employees_rest_days = TupList() self.ts_skill_demand = TupList() self.preference_starts_ts = SuperDict() self.preference_hours_employee = SuperDict() self.preference_slots = SuperDict() + self.employees_rest_days = TupList() + self.fixed_schedule = TupList() # Variables self.works = SuperDict() @@ -55,6 +58,8 @@ def __init__(self, instance, solution=None): self.unmet_max_weekly_work_days_constraint = SuperDict() self.unmet_max_daily_hours_constraint = SuperDict() self.unmet_weekly_hours_constraint = SuperDict() + self.unmet_employee_schedule = SuperDict() + self.unmet_fixed_schedule_constraint = SuperDict() self.initialize() @@ -126,6 +131,9 @@ def initialize(self): self.preference_starts_ts = self.instance.get_employee_preference_start_ts() self.preference_hours_employee = self.instance.get_employee_preference_hours() self.preference_slots = self.instance.get_employee_time_slots_preferences() + self.ts_employees_rest_days = self.instance.get_employee_time_slots_rest_days() + self.employees_rest_days = self.instance.get_employees_rest_days(self.ts_employees_rest_days) + self.fixed_schedule = self.instance.get_employee_fixed_worktable() def create_variables(self): self.works = pl.LpVariable.dicts( @@ -249,6 +257,26 @@ def create_variables(self): ) self.unmet_preference_hours = SuperDict(self.unmet_preference_hours) + # RQ15 + self.unmet_employee_schedule = pl.LpVariable.dicts( + "unmet_employee_schedule", + self.employees_rest_days, + lowBound=0, + upBound=1, + cat=pl.LpContinuous + ) + self.unmet_employee_schedule = SuperDict(self.unmet_employee_schedule) + + # RQ16 + self.unmet_fixed_schedule_constraint = pl.LpVariable.dicts( + "unmet_fixed_schedule_constraint", + self.fixed_schedule, + lowBound=0, + upBound=1, + cat=pl.LpContinuous + ) + self.unmet_fixed_schedule_constraint = SuperDict(self.unmet_fixed_schedule_constraint) + def create_constraints(self, model): # RQ00: objective function - minimize working hours big_m = ( @@ -281,6 +309,10 @@ def create_constraints(self, model): * pl.lpSum(self.unmet_preference_start.values()) + self.instance.get_penalty("rq14") * pl.lpSum(self.unmet_preference_hours.values()) + + self.instance.get_penalty("rq15") + * pl.lpSum(self.unmet_employee_schedule.values()) + + self.instance.get_penalty("rq16") + * pl.lpSum(self.unmet_fixed_schedule_constraint.values()) ) # RQ01: at least one employee at all times @@ -404,4 +436,19 @@ def create_constraints(self, model): <= self.preference_hours_employee[d, e] ) + # RQ15: Employee schedule + if self.instance.get_requirement("rq15") == "soft": + for (ts, d, e) in self.ts_employees_rest_days: + model += self.works[ts, e] <= self.unmet_employee_schedule[d, e] + + # RQ16: Fixed schedule + if self.instance.get_requirement("rq16") != "deactivated": + for (ts, e) in self.fixed_schedule: + model += ( + self.works[ts, e] + + (self.instance.get_requirement("rq16") == "soft") + * self.unmet_fixed_schedule_constraint[ts, e] + == 1 + ) + return model From 1cd3c92f3fbe052cbcb944630b52db2a92178354 Mon Sep 17 00:00:00 2001 From: marioncottard <86973971+marioncottard@users.noreply.github.com> Date: Wed, 4 Oct 2023 20:53:14 +0200 Subject: [PATCH 06/22] Updated documentation (#467) * Updated documentation * Update python versions --------- Co-authored-by: Guillermo Gonzalez-Santander --- QUICK_START_GUIDE.RST | 18 +- cornflow-dags/README.rst | 342 ++++++++++++------ cornflow-server/README.rst | 25 +- .../docs/source/dev/cornflow_client.rst | 10 +- .../docs/source/guides/deploy_solver_new.rst | 58 +-- .../docs/source/main/architecture.rst | 10 +- cornflow-server/docs/source/main/install.rst | 13 +- libs/client/README.rst | 2 +- 8 files changed, 317 insertions(+), 161 deletions(-) diff --git a/QUICK_START_GUIDE.RST b/QUICK_START_GUIDE.RST index d0e19221b..ef12abda1 100644 --- a/QUICK_START_GUIDE.RST +++ b/QUICK_START_GUIDE.RST @@ -122,14 +122,6 @@ If on Windows export should be changed to set. .. raw:: html - - -.. - -Docker ------- - -You will also need to install `Docker Community Edition `_ and `Docker Compose `_. See `here `_ how to deploy your own cornflow server. For cornflow-app @@ -192,10 +184,10 @@ If it is the first time you use cornflow-server, you will then need to setup cor export FLASK_APP=cornflow.app export DATABASE_URL=sqlite:///cornflow.db - python manage.py db upgrade - python manage.py access_init - python manage.py create_service_user --username=airflow --email=airflow_test@admin.com --password=airflow_test_password - python manage.py create_admin_user --username=cornflow --email=cornflow_admin@admin.com --password=cornflow_admin_password + flask db upgrade + flask access_init + flask create_service_user --username=airflow --email=airflow_test@admin.com --password=airflow_test_password + flask create_admin_user --username=cornflow --email=cornflow_admin@admin.com --password=cornflow_admin_password From there, you can launch cornflow-server by navigating to the cornflow-server repository and running: @@ -243,7 +235,9 @@ To do so, you need to clone the repository and create a new folder with the name - :code:`/schemas` - :code:`instance.json`: jsonschema that describes the input data. + - :code:`instance_checks.json`: jsonschema that describes the output of the instance checks. - :code:`solution.json`: jsonschema that describes the output data. + - :code:`solution_checks.json`: jsonschema that describes the output of the solution checks. - :code:`config.json` (optional): jsonschema that describes the configuration. - :code:`/solvers` diff --git a/cornflow-dags/README.rst b/cornflow-dags/README.rst index d5f8124bc..95e0a9e19 100644 --- a/cornflow-dags/README.rst +++ b/cornflow-dags/README.rst @@ -1,3 +1,4 @@ +=============== Cornflow-dags =============== @@ -9,7 +10,7 @@ Uploading a new app / solver Setting the environment ------------------------ -This project requires python 3.5 or above:: +This project requires python 3.7 or above:: python -m venv venv venv/Scripts/activate @@ -20,149 +21,278 @@ Introduction There are several things that are needed when submitting a new solver. -1. a `solve` function. -2. a `name` string. -3. an `instance` dictionary. -4. an `solution` dictionary. -5. a `test_cases` function that returns a list of dictionaries. +1. an `Instance` class. +2. a `Solution` class. +3. an `Experiment class` +4. a `Solver` class +5. an `Application class` -In its most minimalistic form: an app constitutes one dag file that contains all of this. +In its most minimalistic form: an app constitutes one file that contains all of this. In the following lines we will explain each of these concepts while using the graph-coloring example dag. This example can be found in the `DAG/graph_coloring` directory. -The solver ------------- +The Instance class +----------------------------------------- +The Instance class is used to process the input data. +It inherits the class `InstanceCore`, that can be found in cornflow_client.core. -The solver comes in the form of a python function that takes exactly two arguments: `data` and `config`. The first one is a python dictionary with the input data to solve the problem. The second one is also a dictionary with the execution configuration. +In its most basic form, the Instance class should contain at least two fields: schema, and schema_checks. +Those fields should contain the jsonschema used to verify the format of the input data and the input data checks. -This function needs to be named `solve` and returns three things: a python dictionary with the output data, a string that stores the whole log, and a dictionary with the log information processed. Only the first needs to have a value. +In the case of the graph-coloring, the class is defined as:: -The function for the graph-coloring case is:: + import os + from cornflow_client import InstanceCore, get_empty_schema + from cornflow_client.core.tools import load_json + import pytups as pt - from ortools.sat.python import cp_model + + class Instance(InstanceCore): + schema = load_json(os.path.join(os.path.dirname(__file__), "../schemas/input.json")) + schema_checks = get_empty_schema() + + def get_pairs(self): + return pt.TupList((el["n1"], el["n2"]) for el in self.data["pairs"]) + +The class can also define a check() method, that should execute verifications on the input data and return a +dictionary with the errors. +If it defined, this method will be ran before every execution of the solver, to check that the +input data doesn't contain infeasibilities. + +From this class, the input data can be accessed through the `data` field. + +The Solution class +----------------------------------------- +The Solution class is used to process the output data. +It inherits the class `SolutionCore`, that can be found in cornflow_client.core. + +In its most basic form, the Solution class should contain at least one field: schema. +This fields should contain the jsonschema used to verify the format of the output data. + +In the case of the graph-coloring, the class is defined as:: + + import os + from cornflow_client import SolutionCore + from cornflow_client.core.tools import load_json import pytups as pt - from timeit import default_timer as timer - - - def solve(data, config): - """ - :param data: json for the problem - :param config: execution configuration, including solver - :return: solution and log - """ - start = timer() - model = cp_model.CpModel() - input_data = pt.SuperDict.from_dict(data) - pairs = input_data["pairs"] - n1s = pt.TupList(pairs).vapply(lambda v: v["n1"]) - n2s = pt.TupList(pairs).vapply(lambda v: v["n2"]) - nodes = (n1s + n2s).unique2() - max_colors = len(nodes) - 1 - - # variable declaration: - color = pt.SuperDict( - { - node: model.NewIntVar(0, max_colors, "color_{}".format(node)) - for node in nodes - } - ) - for pair in pairs: - model.Add(color[pair["n1"]] != color[pair["n2"]]) - # model.AddAllDifferent(color[n] for n in nodes) - - # TODO: identify maximum cliques and apply constraint on the cliques instead of on pairs - - obj_var = model.NewIntVar(0, max_colors, "total_colors") - model.AddMaxEquality(obj_var, color.values()) - model.Minimize(obj_var) - solver = cp_model.CpSolver() - solver.parameters.max_time_in_seconds = config.get("timeLimit", 10) - status = solver.Solve(model) - if status not in [cp_model.OPTIMAL, cp_model.FEASIBLE]: - return status - color_sol = color.vapply(solver.Value) - - assign_list = color_sol.items_tl().vapply(lambda v: dict(node=v[0], color=v[1])) - solution = dict(assignment=assign_list) - log = "" - status_conv = {4: "Optimal", 2: "Feasible", 3: "Infeasible", 0: "Unknown"} - log = dict( - time=timer() - start, - solver="ortools", - status=status_conv.get(status, "Unknown"), + + + class Solution(SolutionCore): + schema = load_json( + os.path.join(os.path.dirname(__file__), "../schemas/output.json") ) - return solution, "", log -Name and configuration ------------------------ + def get_assignments(self): + return pt.SuperDict({v["node"]: v["color"] for v in self.data["assignment"]}) -You need to choose a name for the solution method, as well as the configuration schema. A quick way of creating a configuration is just creating an empty schema and add some parameters. In the graph-coloring example we add a `timeLimit` property to stop the solver after X seconds:: - name = "graph_coloring" - config = get_empty_schema() - config["properties"] = dict(timeLimit=dict(type="number")) +From this class, the input data can be accessed through the `data` field. -The input schema and output schema +The Experiment class ----------------------------------------- +The Experiment class is used to work on the union of input and output_data. +It inherits the class `ExperimentCore`, that can be found in cornflow_client.core. +An Experiment object is linked to an Instance and a Solution object and can therefore use their data. -Both schemas are built and deployed similarly so we present how the input schema is done. +In its most basic form, the Experiment class should contain at least one field and two methods: +schema_checks, get_objective(), check_solution(). +The method check_solution() should execute verifications on the output data and return a +dictionary with the errors. The method get_objective() should calculate and return the value of the +objective function given the current Instance and Solution. +The field schema_checks should contain the jsonschema used to verify the format of the output data. -The input schema is a json schema file (https://json-schema.org/) that includes all the characteristics of the input data for each dag. This file can be built with many tools (a regular text editor could be enough). +In the case of the graph-coloring, the class is defined as:: -In order to upload it, you need to have an `instance` variable available in your dag file. + from cornflow_client import ExperimentCore + from cornflow_client.core.tools import load_json + from .instance import Instance + from .solution import Solution + import os -In the case of the graph-coloring, these variables are imported from the package:: - with open(os.path.join(os.path.dirname(__file__), "input.json"), "r") as f: - instance = json.load(f) - with open(os.path.join(os.path.dirname(__file__), "output.json"), "r") as f: - solution = json.load(f) + class Experiment(ExperimentCore): + schema_checks = load_json( + os.path.join(os.path.dirname(__file__), "../schemas/solution_checks.json") + ) -This just imports the `input.json` and `output.json` files as python dictionaries. You can check either file to see how they are structured. + @property + def instance(self) -> Instance: + return super().instance -Airflow functions and name ------------------------------ -There are some basic functions and declarations that need to be created. The easiest is to just copy the ones from and example and adapt them if needed:: + @property + def solution(self) -> Solution: + return super().solution - from airflow import DAG - from airflow.operators.python import PythonOperator - import cornflow_client.airflow.dag_utilities as utils + @solution.setter + def solution(self, value): + self._solution = value - dag = DAG(name, default_args=utils.default_args, schedule_interval=None) - def solve_hk(**kwargs): - return utils.cf_solve(solve, name, EnvironmentVariablesBackend(), **kwargs) + def get_objective(self) -> float: + return self.solution.get_assignments().values_tl().unique().len() - graph_coloring = PythonOperator(task_id=name, python_callable=solve_hk, dag=dag) + def check_solution(self, *args, **kwargs) -> dict: + # if a pair of nodes have the same colors: that's a problem + colors = self.solution.get_assignments() + pairs = self.instance.get_pairs() + errors = [ + {"n1": n1, "n2": n2} for (n1, n2) in pairs if colors[n1] == colors[n2] + ] + return dict(pairs=errors) -Unit tests +From this class, the instance can be accessed through the `instance` field, and the solution can be +accessed through the `solution` field. + +The solver ------------ -The `test_cases` function is used in the unittests to be sure the solver works as intended. In the graph-coloring example we read the examples from the the `data` directory and transform them to the correct format:: +The solver is the part of the app that takes care of the resolution of the problem. An app can contain +several ones. +The solver comes in the form of a python class. It inherits the Experiment class. As such, it is also +linked to an Instance and a Solution object and can therefore use their data. + +In its most basic form, the Solver class should contain at least a `solve()` method. This method should +take exactly one argument: a dictionary with the execution configuration. It should return a dictionary +with two keys: `status` and `status_sol`. `status` should contain the status of the execution (optimal, +unbounded, time_limit...) while `status_sol` should return the information of whether the execution +has found a solution or not. The mappings of both these statuses are defined in +cornflow_client.constants. + +The class for the graph-coloring case is:: + + from ortools.sat.python import cp_model + from cornflow_client.constants import ( + ORTOOLS_STATUS_MAPPING, + SOLUTION_STATUS_FEASIBLE, + SOLUTION_STATUS_INFEASIBLE, + ) + import pytups as pt + from ..core import Solution, Experiment + + class OrToolsCP(Experiment): + def solve(self, options: dict): + model = cp_model.CpModel() + input_data = pt.SuperDict.from_dict(self.instance.data) + pairs = input_data["pairs"] + n1s = pt.TupList(pairs).vapply(lambda v: v["n1"]) + n2s = pt.TupList(pairs).vapply(lambda v: v["n2"]) + nodes = (n1s + n2s).unique2() + max_colors = len(nodes) - 1 + + # variable declaration: + color = pt.SuperDict( + { + node: model.NewIntVar(0, max_colors, "color_{}".format(node)) + for node in nodes + } + ) + for pair in pairs: + model.Add(color[pair["n1"]] != color[pair["n2"]]) + + obj_var = model.NewIntVar(0, max_colors, "total_colors") + model.AddMaxEquality(obj_var, color.values()) + model.Minimize(obj_var) + solver = cp_model.CpSolver() + solver.parameters.max_time_in_seconds = options.get("timeLimit", 10) + termination_condition = solver.Solve(model) + if termination_condition not in [cp_model.OPTIMAL, cp_model.FEASIBLE]: + return dict( + status=ORTOOLS_STATUS_MAPPING.get(termination_condition), + status_sol=SOLUTION_STATUS_INFEASIBLE + ) + color_sol = color.vapply(solver.Value) + + assign_list = color_sol.items_tl().vapply(lambda v: dict(node=v[0], color=v[1])) + self.solution = Solution(dict(assignment=assign_list)) + + return dict( + status=ORTOOLS_STATUS_MAPPING.get(termination_condition), + status_sol=SOLUTION_STATUS_FEASIBLE + ) + +The class can also defined a string field `log`. If it does, +the log will be saved in cornflow at the end of the execution with the solution data, so that it +can be consulted by the user. + +The Application +----------------------- + +The Application class is the base of the app. It links the different resolution methods and takes care +of the connection with the server. +It inherits the class `ApplicationCore`, that can be found in cornflow_client.core. + +An Application should contain several fields: - def test_cases(): - file_dir = os.path.join(os.path.dirname(__file__), "..", "data") - files = os.listdir(file_dir) - test_files = pt.TupList(files).vfilter(lambda v: v.startswith("gc_")) - return [read_file(os.path.join(file_dir, fileName)) for fileName in test_files] +- a string `name` +- an `instance` object that contains the Instance class defined earlier +- a `solution` object that contains the Solution class defined earlier +- a `solvers` dictionary that contains a mapping to the different solvers defined earlier +- a `schema` object that contains the jsonschema corresponding to the configuration dictionaries. +A quick way of creating a configuration is just creating an empty schema and add some parameters. +In the graph-coloring example we add a `timeLimit` property to stop the solver after X seconds. +- a `test_cases` property that should return a list of test instance datasets. +The `test_cases` function is used in the unittests to be sure the solver works as intended. +In the graph-coloring example we read the examples from the the `data` directory and transform +them to the correct format. +The class for the graph-coloring case is:: + + from cornflow_client import get_empty_schema, ApplicationCore + from typing import List, Dict + import pytups as pt + import os + + from .solvers import OrToolsCP + from .core import Instance, Solution - def read_file(filePath): - with open(filePath, "r") as f: - contents = f.read().splitlines() - pairs = ( - pt.TupList(contents[1:]) - .vapply(lambda v: v.split(" ")) - .vapply(lambda v: dict(n1=int(v[0]), n2=int(v[1]))) + class GraphColoring(ApplicationCore): + name = "graph_coloring" + instance = Instance + solution = Solution + solvers = dict(default=OrToolsCP) + schema = get_empty_schema( + properties=dict(timeLimit=dict(type="number")), solvers=list(solvers.keys()) ) - return dict(pairs=pairs) -To be sure that the the the solution method is tested, you need to edit the `tests/test_dags.py` file and add a reference to your solver:: + @property + def test_cases(self) -> List[Dict]: + def read_file(filePath): + with open(filePath, "r") as f: + contents = f.read().splitlines() + + pairs = ( + pt.TupList(contents[1:]) + .vapply(lambda v: v.split(" ")) + .vapply(lambda v: dict(n1=int(v[0]), n2=int(v[1]))) + ) + return dict(pairs=pairs) + + file_dir = os.path.join(os.path.dirname(__file__), "data") + files = os.listdir(file_dir) + test_files = pt.TupList(files).vfilter(lambda v: v.startswith("gc_")) + return [read_file(os.path.join(file_dir, fileName)) for fileName in test_files] + +The jsonschemas +----------------------------------------- + +All jsonschemas are built and deployed similarly so we present how the input schema is done. +A jsonschema is a json schema file (https://json-schema.org/) that includes all the characteristics of the data for each dag. +This file can be built with many tools (a regular text editor could be enough). +You can check the `DAG/graph_coloring/schemas` directory to see how they are structured. + +Unit tests +------------ + +To be sure that the the the solution method is tested, you need to edit the `tests/test_dags.py` file +and add a reference to your solver:: class GraphColor(BaseDAGTests.SolvingTests): def setUp(self): super().setUp() - self.app = _import_file("graph_coloring") + from DAG.graph_coloring import GraphColoring + + self.app = GraphColoring() + self.config = dict(msg=False) Then, you can execute the unittests for your solver with the following command:: diff --git a/cornflow-server/README.rst b/cornflow-server/README.rst index c22b3c3fe..47df840c0 100644 --- a/cornflow-server/README.rst +++ b/cornflow-server/README.rst @@ -40,19 +40,33 @@ Cornflow helps you formalize your problem by proposing development guidelines. I Installation instructions ------------------------------- -Cornflow is tested with Ubuntu 20.04, python >= 3.5 and git. +Cornflow is tested with Ubuntu 20.04, python >= 3.8 and git. Download the Cornflow project and install requirements:: - git clone git@github.com:baobabsoluciones/cornflow.git - cd cornflow-server python3 -m venv venv - venv/bin/pip3 install -r requirements-dev.txt + venv/bin/pip3 install cornflow + +initialize the sqlite database:: + + source venv/bin/activate + export FLASK_APP=cornflow.app + export DATABASE_URL=sqlite:///cornflow.db + flask db upgrade + flask access_init + flask create_service_user -u airflow -e airflow_test@admin.com -p airflow_test_password + flask create_admin_user -u cornflow -e cornflow_admin@admin.com -p cornflow_admin_password + activate the virtual environment and run Cornflow:: source venv/bin/activate export FLASK_APP=cornflow.app + export SECRET_KEY=THISNEEDSTOBECHANGED + export DATABASE_URL=sqlite:///cornflow.db + export AIRFLOW_URL=http://127.0.0.1:8080/ + export AIRFLOW_USER=airflow_user + export AIRFLOW_PWD=airflow_pwd flask run **Cornflow needs a running installation of Airflow to operate and more configuration**. Check `the installation docs `_ for more details on installing airflow, configuring the application and initializing the database. @@ -135,8 +149,7 @@ Using cornflow to deploy a solution method To deploy a cornflow solution method, the following tasks need to be accomplished: -#. Create I/O schemas for the new problem (e.g., “TSP format”). -#. Create a solve function (e.g., a 2-opt heuristic). +#. Create an Application for the new problem #. Do a PR to a compatible repo linked to a server instance (e.g., like `this one `_). For more details on each part, check the `deployment guide `_. diff --git a/cornflow-server/docs/source/dev/cornflow_client.rst b/cornflow-server/docs/source/dev/cornflow_client.rst index 841a41db0..5d68b9f8b 100644 --- a/cornflow-server/docs/source/dev/cornflow_client.rst +++ b/cornflow-server/docs/source/dev/cornflow_client.rst @@ -65,9 +65,12 @@ Solving status .. data:: cornflow_client.constants.STATUS_INFEASIBLE .. data:: cornflow_client.constants.STATUS_UNBOUNDED .. data:: cornflow_client.constants.STATUS_UNDEFINED -.. data:: cornflow_client.constants.STATUS_TIME_LIMIT +.. data:: cornflow_client.constants.STATUS_FEASIBLE .. data:: cornflow_client.constants.STATUS_MEMORY_LIMIT .. data:: cornflow_client.constants.STATUS_NODE_LIMIT +.. data:: cornflow_client.constants.STATUS_TIME_LIMIT +.. data:: cornflow_client.constants.STATUS_LICENSING_PROBLEM +.. data:: cornflow_client.constants.STATUS_QUEUED ============================================================ ========== Constant Value @@ -77,9 +80,12 @@ Constant Value :data:`cornflow_client.constants.STATUS_INFEASIBLE` -1 :data:`cornflow_client.constants.STATUS_UNBOUNDED` -2 :data:`cornflow_client.constants.STATUS_UNDEFINED` -3 -:data:`cornflow_client.constants.STATUS_TIME_LIMIT` 2 +:data:`cornflow_client.constants.STATUS_FEASIBLE` 2 :data:`cornflow_client.constants.STATUS_MEMORY_LIMIT` 3 :data:`cornflow_client.constants.STATUS_NODE_LIMIT` 4 +:data:`cornflow_client.constants.STATUS_TIME_LIMIT` 5 +:data:`cornflow_client.constants.STATUS_LICENSING_PROBLEM` -5 +:data:`cornflow_client.constants.STATUS_QUEUED` -7 ============================================================ ========== diff --git a/cornflow-server/docs/source/guides/deploy_solver_new.rst b/cornflow-server/docs/source/guides/deploy_solver_new.rst index 16f49b60e..aa2def821 100644 --- a/cornflow-server/docs/source/guides/deploy_solver_new.rst +++ b/cornflow-server/docs/source/guides/deploy_solver_new.rst @@ -30,18 +30,29 @@ We will go over each of the required properties below. Instance class --------------- -This is just a subclass of :py:class:`~cornflow_client.core.instance.InstanceCore`. There are many default methods that can be overwritten (``to_dict``, ``from_dict``, etc.). The only required property is the ``schema``. Here we have just imported a file with the corresponding json-schema. If you want to know how to define a json-schema, check the section :ref:`Write a json-schema`. +This is just a subclass of :py:class:`~cornflow_client.core.instance.InstanceCore`. There are many default methods that can be overwritten (``to_dict``, ``from_dict``, etc.). The only required properties are the ``schema`` and ``schema_checks``. Here we have just imported a file with the corresponding json-schema for the ``schema``, and defined an empty schema for the ``schema_checks``. If you want to know how to define a json-schema, check the section :ref:`Write a json-schema`. +The instance can also define a check() method. .. code-block:: python class Instance(InstanceCore): schema = load_json(os.path.join(os.path.dirname(__file__), "input.json")) + schema_checks = get_empty_schema() + +check +***************** + +``check`` returns a dictionary of lists. Each key in the dictionary represents a specific validation. Each entry of the list represents a violation of the requirement checked in this validation. + +schema_checks +***************** +``schema_checks`` returns a jsonschema corresponding to the output of the ``check`` method. Solution class --------------- -Very similar to the Instance. The Solution is just a subclass of :py:class:`~cornflow_client.core.solution.SolutionCore`. +Very similar to the Instance. The Solution is just a subclass of :py:class:`~cornflow_client.core.solution.SolutionCore`. The only required property is the ``schema``. .. code-block:: python @@ -51,7 +62,7 @@ Very similar to the Instance. The Solution is just a subclass of :py:class:`~cor Experiment class ----------------- -Although not strictly necessary, it is usually good practice to define an Experiment class that subclasses :py:class:`~cornflow_client.core.experiment.ExperimentCore`. This class takes as input an :ref:`Instance class` and a :ref:`Solution class`. Its purpose is to evaluate and validate a given solution. To achieve this, the class should implement at least two methods ``get_objective`` and ``check_solution``. +Although not strictly necessary, it is usually good practice to define an Experiment class that subclasses :py:class:`~cornflow_client.core.experiment.ExperimentCore`. This class takes as input an :ref:`Instance class` and a :ref:`Solution class`. Its purpose is to evaluate and validate a given solution. To achieve this, the class should implement at least two methods ``get_objective`` and ``check_solution`` and a field ``schema_checks``. get_objective ***************** @@ -62,30 +73,21 @@ get_objective check_solution ***************** -``check_solution`` returns a dictionary of dictionaries. Each key in the first dictionary represents a specific validation. Each key in the second dictionary represents the domain of a given validation where the solution violates its requirement. The value of the second dictionary represents the extent of the violation. +``check_solution`` returns a dictionary of lists. Each key in the dictionary represents a specific validation. Each entry of the list represents a violation of the requirement checked in this validation. In the example below for the TSP, a possible value for ``check_solution()`` could be: .. code-block:: python { - "missing_nodes": {5: 1, 6: 1} + "missing_nodes": [{"node": 5}, {"node": 6}] } -Which implies that the node 5 and node 6 have not been visited in the solution. The value 1 in this case is not used. - - -It's important that there should not be more than two dictionary indentation. For example, this would be invalid: - -.. code-block:: python - - { - "missing_nodes": { - "missing_nodes_1": {5: 1, 6: 1}, - "missing_nodes_2": {1: 1, 2: 2}, - } - } +Which implies that the node 5 and node 6 have not been visited in the solution. +schema_checks +***************** +``schema_checks`` returns a jsonschema corresponding to the output of the ``check_solution`` method. Example @@ -95,6 +97,8 @@ Example class Experiment(ExperimentCore): + schema_checks = get_empty_schema() + def get_objective(self) -> float: # we get a sorted list of nodes by position route = ( @@ -112,9 +116,9 @@ Example def check_solution(self, *args, **kwargs) -> dict: nodes_in = TupList(v["n1"] for v in self.instance.data["arcs"]).to_set() nodes_out = TupList(n["node"] for n in self.solution.data["route"]).to_set() - missing_nodes = {n: 1 for n in (nodes_in - nodes_out)} + missing_nodes = [{"node": n} for n in (nodes_in - nodes_out)] positions = TupList(n["pos"] for n in self.solution.data["route"]).to_set() - missing_positions = {p: 1 for p in set(range(len(nodes_in))) - positions} + missing_positions = [{"position": p} for p in set(range(len(nodes_in))) - positions] return SuperDict( missing_nodes=missing_nodes, missing_positions=missing_positions ) @@ -136,8 +140,12 @@ Each solver is a subclass of the :ref:`Experiment class` and should define one a .kvapply(lambda k, v: dict(pos=k, node=v)) ) self.solution = Solution(dict(route=nodes)) - return {} + return dict( + status_sol=SOLUTION_STATUS_FEASIBLE, + status=STATUS_UNDEFINED + ) +The output of the ``solve`` method should be a dictionary contains the state of the resolution. The status mapping can be found in ``cornflow_client.constants``. The ``status_sol`` item should indicate whether the execution has found a solution or not, while the ``status`` item should return the state of the resolution (optimal, stopped because of time limit, unfeasible...). More than one solution method can be defined. This is why they are given in a dictionary to the :ref:`Application class`. We use them as a catalogue when deciding to solve a problem. @@ -237,6 +245,7 @@ In this example we put everything inside the ``__init__.py`` (except the json-sc class Instance(InstanceCore): schema = load_json(os.path.join(os.path.dirname(__file__), "input.json")) + schema_checks = get_empty_schema() class Solution(SolutionCore): @@ -244,6 +253,8 @@ In this example we put everything inside the ``__init__.py`` (except the json-sc class Experiment(ExperimentCore): + schema_checks = get_empty_schema() + def get_objective(self) -> float: # we get a sorted list of nodes by position route = ( @@ -278,7 +289,10 @@ In this example we put everything inside the ``__init__.py`` (except the json-sc .kvapply(lambda k, v: dict(pos=k, node=v)) ) self.solution = Solution(dict(route=nodes)) - return {} + return dict( + status_sol=SOLUTION_STATUS_FEASIBLE, + status=STATUS_UNDEFINED + ) class TspApp(ApplicationCore): diff --git a/cornflow-server/docs/source/main/architecture.rst b/cornflow-server/docs/source/main/architecture.rst index 122e25957..19f309df5 100644 --- a/cornflow-server/docs/source/main/architecture.rst +++ b/cornflow-server/docs/source/main/architecture.rst @@ -54,17 +54,17 @@ Main data flows Create instance (data): #. Client calls Cornflow and sends instance. -#. Cornflow asks airflow for the schema of the instance and validates the instance matches the schema. +#. Cornflow validates the instance matches the app's jsonschema. #. Cornflow saves the instance and returns the instance code to client. Solve instance (instance, config, dag): -#. Client calls Cornflow and gives instance code and execution configuration. -#. Cornflow asks cornflow for schema and validates the instance matches the dag to execute. +#. Client calls Cornflow and gives instance code, execution configuration and eventually an existing solution. +#. Cornflow validates the instance matches the jsonschema of the dag to execute. #. Cornflow calls airflow dag and assigns dagrun code to execution. #. Cornflow creates execution and returns the execution code to client. #. Airflow creates a rundag for the selected dag and sends it to a worker. -#. The worker asks Cornflow for the instance and the config. +#. The worker asks Cornflow for the instance, the config, and eventually the solution data. #. The worker solves the problem. #. The worker sends Cornflow the results (solution and log) of the execution. @@ -97,7 +97,7 @@ Retrieve status (execution): Retrieve schema: #. Client asks Cornflow for the schema to a problem. -#. Cornflow asks Airflow for the schema of a problem. +#. If Cornflow does not know it: it asks Airflow for the schema of a problem. #. Airflow returns the schema if it exists. Get instance data: diff --git a/cornflow-server/docs/source/main/install.rst b/cornflow-server/docs/source/main/install.rst index 48a5a99e1..f33849956 100644 --- a/cornflow-server/docs/source/main/install.rst +++ b/cornflow-server/docs/source/main/install.rst @@ -12,21 +12,20 @@ Install cornflow Cornflow consists of two projects: cornflow (itself) and airflow (from apache). They are conceived to be deployed independently. Here we will explain the "development deploy" that consists on installing them in the same machine. -Download the Cornflow project:: +Create and activate the virtual environment:: - git clone git@github.com:baobabsoluciones/cornflow.git - cd cornflow-server python3 -m venv venv - venv/bin/pip3 install -r requirements-dev.txt - -activate the virtual environment:: - source venv/bin/activate or, in windows:: + python3 -m venv venv venv/Scripts/activate +Install the Cornflow library:: + + venv/bin/pip3 install cornflow + Setup cornflow database ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/libs/client/README.rst b/libs/client/README.rst index 6a8f537a7..d5f781520 100644 --- a/libs/client/README.rst +++ b/libs/client/README.rst @@ -6,7 +6,7 @@ The aim of this repository is to have a client to use to connect to a deployed c Requirements ~~~~~~~~~~~~ -* python >= 3.6 +* python >= 3.8 Install cornflow-client ~~~~~~~~~~~~~~~~~~~~~~~~ From 82a0d66a7b469e62381b64e48b699736d962e756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Wed, 4 Oct 2023 22:55:28 +0200 Subject: [PATCH 07/22] Add sendgrid on providers installed (#479) Co-authored-by: Guillermo Gonzalez-Santander --- cornflow-server/airflow_config/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cornflow-server/airflow_config/Dockerfile b/cornflow-server/airflow_config/Dockerfile index 632b43a45..e4b1ad305 100644 --- a/cornflow-server/airflow_config/Dockerfile +++ b/cornflow-server/airflow_config/Dockerfile @@ -51,7 +51,7 @@ RUN apt update -y && apt-get install -y --no-install-recommends \ wget # install Airflow and extras: celery,postgres and redis -RUN pip install "apache-airflow[celery,google,postgres,redis]==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" +RUN pip install "apache-airflow[celery,google,postgres,redis,sendgrid]==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" RUN pip install python-ldap RUN pip install GitPython RUN pip install cmake From b0f0195253cb70555f501f4948fa1e4cfc9710ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandra=20Gal=C3=A1n?= <99278460+AlejandraGalan@users.noreply.github.com> Date: Thu, 5 Oct 2023 11:01:04 +0400 Subject: [PATCH 08/22] Feature/email notification (#470) * Adding the notification email on failure * Adding new variable notify to ApplicationCore() * Adding new function callback_email() to utilities * Correcting format ( using black ) * Correcting format ( using black ), including imports inside function and adding msc environment variable * Removing duplicated "import logging" * Small adjustments to PR --------- Co-authored-by: Guillermo Gonzalez-Santander --- cornflow-dags/DAG/activate_dags.py | 15 +++++++-- .../cornflow_client/airflow/dag_utilities.py | 32 ++++++++++++++++++- .../cornflow_client/core/application.py | 7 ++++ 3 files changed, 50 insertions(+), 4 deletions(-) diff --git a/cornflow-dags/DAG/activate_dags.py b/cornflow-dags/DAG/activate_dags.py index ec07893df..df57f14f1 100644 --- a/cornflow-dags/DAG/activate_dags.py +++ b/cornflow-dags/DAG/activate_dags.py @@ -1,8 +1,9 @@ +import cornflow_client.airflow.dag_utilities as utils from airflow import DAG +from airflow.operators.python import PythonOperator from airflow.secrets.environment_variables import EnvironmentVariablesBackend -import cornflow_client.airflow.dag_utilities as utils + from update_all_schemas import get_new_apps -from airflow.operators.python import PythonOperator def create_dag(app): @@ -27,7 +28,15 @@ def solve(**kwargs): **kwargs ) with dag: - t1 = PythonOperator(task_id=app.name, python_callable=solve) + if not app.notify: + t1 = PythonOperator(task_id=app.name, python_callable=solve) + else: + t1 = PythonOperator( + task_id=app.name, + python_callable=solve, + on_failure_callback=utils.callback_email, + ) + return dag diff --git a/libs/client/cornflow_client/airflow/dag_utilities.py b/libs/client/cornflow_client/airflow/dag_utilities.py index 8b803dd4d..8cdb69814 100644 --- a/libs/client/cornflow_client/airflow/dag_utilities.py +++ b/libs/client/cornflow_client/airflow/dag_utilities.py @@ -10,7 +10,6 @@ from datetime import datetime, timedelta from urllib.parse import urlparse, urljoin - # Imports from modules from cornflow_client import CornFlow, CornFlowApiError @@ -314,6 +313,37 @@ def cf_check(fun, dag_name, secrets, **kwargs): ) +def callback_email(context): + from airflow.utils.email import send_email + from airflow.secrets.environment_variables import EnvironmentVariablesBackend + + path_to_log = ( + f"./logs/{context['dag'].dag_id}/" + f"{context['ti'].task_id}/{context['ts']}/1.log" + ) + environment = EnvironmentVariablesBackend().get_variable("ENVIRONMENT") + notification_email = EnvironmentVariablesBackend().get_variable( + "NOTIFICATION_EMAIL" + ) + environment_name = EnvironmentVariablesBackend().get_variable("ENVIRONMENT_NAME") + + title = f"Airflow. {environment_name} ({environment}). DAG/task error: {context['dag'].dag_id}/{context['ti'].task_id} Failed" + body = f""" + The DAG/task {context['dag'].dag_id}/{context['ti'].task_id} has failed. +
+ The log is attached. + """ + + send_email( + to=[ + notification_email, + ], + subject=title, + html_content=body, + files=[path_to_log], + ) + + class NoSolverException(Exception): pass diff --git a/libs/client/cornflow_client/core/application.py b/libs/client/cornflow_client/core/application.py index b076d66e8..6230b9d9d 100644 --- a/libs/client/cornflow_client/core/application.py +++ b/libs/client/cornflow_client/core/application.py @@ -33,6 +33,13 @@ class ApplicationCore(ABC): """ The application template. """ + # We create a new attribute controlling the use of the notification mail function + def __init__(self): + self._notify = False + + @property + def notify(self) -> bool: + return self._notify @property @abstractmethod From 8590599c60d600b6de6ca957aa2eb5d5cb33e20c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Tue, 10 Oct 2023 17:15:38 +0200 Subject: [PATCH 09/22] Feature/test deployed dags (#481) * DAG to run the examples automatically * Changed the way we check for the notification parameter * Use getattr * Small fixes * Another change * logging * Parse json * Don't send solver * Added notify to rostering * Updated path to log based on new log folder structure * Small adjustment to run deployed dags * Change the logging * Small changes to dags and cornflow server so the config get extended with the default values defined. * Deleted unused print * Changes to dags to be able to be solved automatically * Changed config schema of facility_location * Small change to facility location * Change time limit * Added seconds * Small change to schema generator to debug * changed print for click.echo * Commented out the schema from models cli command and all its related code * Added more unit testing for the executions. Deleted unreacheble code on executions --- cornflow-dags/DAG/activate_dags.py | 3 +- cornflow-dags/DAG/bar_cutting/__init__.py | 10 - .../DAG/bar_cutting/schemas/config.json | 4 +- .../DAG/facility_location/__init__.py | 12 +- .../DAG/facility_location/schemas/config.json | 14 + cornflow-dags/DAG/run_deployed_dags.py | 126 +++++++++ .../solvers/right_corner_model.py | 14 +- cornflow-dags/DAG/update_all_schemas.py | 13 +- cornflow-dags/DAG/update_dag_registry.py | 9 +- cornflow-server/cornflow/cli/schemas.py | 121 ++++---- .../cornflow/cli/tools/schema_generator.py | 6 +- .../cornflow/endpoints/execution.py | 44 +-- cornflow-server/cornflow/models/dag.py | 3 +- cornflow-server/cornflow/models/execution.py | 10 + cornflow-server/cornflow/shared/validators.py | 56 +++- cornflow-server/cornflow/tests/const.py | 4 + .../cornflow/tests/data/bad_execution.json | 19 ++ .../tests/data/new_execution_solution.json | 123 +++++++++ .../cornflow/tests/unit/test_executions.py | 65 ++++- .../cornflow/tests/unit/test_licenses.py | 45 +++ .../tests/unit/test_schema_from_models.py | 259 +++++++++--------- .../cornflow_client/airflow/dag_utilities.py | 5 +- 22 files changed, 704 insertions(+), 261 deletions(-) create mode 100644 cornflow-dags/DAG/facility_location/schemas/config.json create mode 100644 cornflow-dags/DAG/run_deployed_dags.py create mode 100644 cornflow-server/cornflow/tests/data/bad_execution.json create mode 100644 cornflow-server/cornflow/tests/data/new_execution_solution.json create mode 100644 cornflow-server/cornflow/tests/unit/test_licenses.py diff --git a/cornflow-dags/DAG/activate_dags.py b/cornflow-dags/DAG/activate_dags.py index df57f14f1..837952081 100644 --- a/cornflow-dags/DAG/activate_dags.py +++ b/cornflow-dags/DAG/activate_dags.py @@ -28,7 +28,8 @@ def solve(**kwargs): **kwargs ) with dag: - if not app.notify: + notify = getattr(app, "notify", True) + if not notify: t1 = PythonOperator(task_id=app.name, python_callable=solve) else: t1 = PythonOperator( diff --git a/cornflow-dags/DAG/bar_cutting/__init__.py b/cornflow-dags/DAG/bar_cutting/__init__.py index 1837f592f..49ace3392 100644 --- a/cornflow-dags/DAG/bar_cutting/__init__.py +++ b/cornflow-dags/DAG/bar_cutting/__init__.py @@ -17,12 +17,9 @@ class BarCutting(ApplicationCore): solution = Solution solvers = dict(mip=MipModel, CG=ColumnGeneration) schema = load_json(os.path.join(os.path.dirname(__file__), "./schemas/config.json")) - schema["properties"]["solver"]["enum"].append("mip.cbc") - schema["properties"]["solver"]["enum"].append("CG.cbc") @property def test_cases(self) -> List[Union[Dict, Tuple[Dict, Dict]]]: - options_instance = ["data/example_instance_1.json"] options_solution = ["data/example_solution_1.json"] @@ -44,10 +41,3 @@ def test_cases(self) -> List[Union[Dict, Tuple[Dict, Dict]]]: ) for i in range(len(options_instance)) ] - - def get_solver(self, name: str = "mip") -> Union[Type[Experiment], None]: - if "." in name: - solver, _ = name.split(".") - else: - solver = name - return self.solvers.get(solver) diff --git a/cornflow-dags/DAG/bar_cutting/schemas/config.json b/cornflow-dags/DAG/bar_cutting/schemas/config.json index e7eaf88f7..d857a6310 100644 --- a/cornflow-dags/DAG/bar_cutting/schemas/config.json +++ b/cornflow-dags/DAG/bar_cutting/schemas/config.json @@ -4,8 +4,8 @@ "properties": { "solver": { "type": "string", - "enum": ["mip", "CG"], - "default": "mip" + "enum": ["mip", "CG", "mip.cbc", "CG.cbc"], + "default": "mip.cbc" }, "timeLimit": { "type": "number" diff --git a/cornflow-dags/DAG/facility_location/__init__.py b/cornflow-dags/DAG/facility_location/__init__.py index 0e4f1fa9d..f49073d91 100644 --- a/cornflow-dags/DAG/facility_location/__init__.py +++ b/cornflow-dags/DAG/facility_location/__init__.py @@ -11,17 +11,7 @@ class FacilityLocation(ApplicationCore): instance = Instance solution = Solution solvers = dict(Pyomo=PyomoSolver) - schema = get_empty_schema( - properties=dict(timeLimit=dict(type="number")), - solvers=list(solvers.keys()) + ["Pyomo.cbc"], - ) - - def get_solver(self, name: str = "Pyomo") -> Union[Type[Experiment], None]: - if "." in name: - solver, _ = name.split(".") - else: - solver = name - return self.solvers.get(solver) + schema = load_json(os.path.join(os.path.dirname(__file__), "./schemas/config.json")) @property def test_cases(self): diff --git a/cornflow-dags/DAG/facility_location/schemas/config.json b/cornflow-dags/DAG/facility_location/schemas/config.json new file mode 100644 index 000000000..441d4605a --- /dev/null +++ b/cornflow-dags/DAG/facility_location/schemas/config.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "solver": { + "type": "string", + "enum": ["Pyomo", "Pyomo.cbc"], + "default": "Pyomo.cbc" + }, + "timeLimit": { + "type": "number" + } + } +} diff --git a/cornflow-dags/DAG/run_deployed_dags.py b/cornflow-dags/DAG/run_deployed_dags.py new file mode 100644 index 000000000..d2738eb84 --- /dev/null +++ b/cornflow-dags/DAG/run_deployed_dags.py @@ -0,0 +1,126 @@ +import json +import logging +import time +from datetime import datetime, timedelta + +from airflow import DAG +from airflow.models import Variable +from airflow.operators.python import PythonOperator +from airflow.secrets.environment_variables import EnvironmentVariablesBackend +from airflow.utils.db import create_session +from cornflow_client import CornFlowApiError +from cornflow_client.airflow.dag_utilities import connect_to_cornflow + +default_args = { + "owner": "baobab", + "depends_on_past": False, + "start_date": datetime(2020, 2, 1), + "email": [""], + "email_on_failure": False, + "email_on_retry": False, + "retries": -1, + "retry_delay": timedelta(minutes=1), + "catchup": False, +} + +logger = logging.getLogger("airflow.task") + + +def run_examples(**kwargs): + with create_session() as session: + current_examples = { + var.key: json.loads(var.get_val())["instance_1"] + for var in session.query(Variable) + if "_examples" in var.key + } + + current_examples = {k: v for k, v in current_examples.items() if v != {}} + + cf_client = connect_to_cornflow(EnvironmentVariablesBackend()) + executions = [] + + for key, instance in current_examples.items(): + schema = key.split("z_")[1].split("_examples")[0] + + try: + response = cf_client.create_instance( + data=instance, name=f"Automatic_instance_run_{schema}", schema=schema + ) + except CornFlowApiError as e: + logger.info(e) + logger.info( + f"Instance example for schema {schema} had an error on creation" + ) + continue + + instance_id = response["id"] + + config = {"timeLimit": 60, "msg": True, "seconds": 60} + + try: + response = cf_client.create_execution( + instance_id=instance_id, + config=config, + name=f"Automatic_execution_run_{schema}", + schema=schema, + ) + except CornFlowApiError as e: + logger.info(e) + logger.info( + f"Execution example for schema {schema} had an error on creation" + ) + continue + + execution_id = response["id"] + executions.append((execution_id, schema)) + + limit = (len(executions) + 1) * 60 + start = datetime.utcnow() + + while executions and datetime.utcnow() - start < timedelta(seconds=limit): + for index, (execution, schema) in enumerate(executions): + try: + response = cf_client.get_status(execution_id=execution) + except CornFlowApiError as e: + logger.info(e) + logger.info( + f"Execution {execution} of schema {schema} had an error on status retrieval" + ) + executions.pop(index) + continue + + if response["state"] in (1, 2): + logger.info( + f"Execution {execution} of schema {schema} finished successfully" + ) + executions.pop(index) + elif response["state"] in (-1, -2, -3, -4, -5, -6): + logger.info(f"Execution {execution} of schema {schema} failed") + executions.pop(index) + else: + continue + + time.sleep(15) + + if len(executions): + for execution, schema in executions: + logger.info( + f"Execution {execution} of schema {schema} could not be checked" + ) + + logger.info("Automatic test process finished") + + +dag = DAG( + "run_deployed_models", + default_args=default_args, + schedule_interval=None, + catchup=False, +) + +run_examples_task = PythonOperator( + task_id="run_examples", + python_callable=run_examples, + provide_context=True, + dag=dag, +) diff --git a/cornflow-dags/DAG/two_dimension_bin_packing/solvers/right_corner_model.py b/cornflow-dags/DAG/two_dimension_bin_packing/solvers/right_corner_model.py index 4386b74f9..06808399a 100644 --- a/cornflow-dags/DAG/two_dimension_bin_packing/solvers/right_corner_model.py +++ b/cornflow-dags/DAG/two_dimension_bin_packing/solvers/right_corner_model.py @@ -2,7 +2,7 @@ STATUS_TIME_LIMIT, SOLUTION_STATUS_FEASIBLE, SOLUTION_STATUS_INFEASIBLE, - PYOMO_STOP_MAPPING + PYOMO_STOP_MAPPING, ) from pytups import SuperDict from two_dimension_bin_packing.core import Experiment, Solution @@ -257,6 +257,7 @@ def solve(self, options): _, solver_name = solver_name.split(".") # Setting solver + # TODO: review solver options translation if solver_name == "gurobi": opt = SolverFactory(solver_name, solver_io="python") else: @@ -274,14 +275,12 @@ def solve(self, options): # Check status if status in ["error", "unknown", "warning"]: return dict( - status=termination_condition, - status_sol=SOLUTION_STATUS_INFEASIBLE + status=termination_condition, status_sol=SOLUTION_STATUS_INFEASIBLE ) elif status == "aborted": if termination_condition != STATUS_TIME_LIMIT: return dict( - status=termination_condition, - status_sol=SOLUTION_STATUS_INFEASIBLE + status=termination_condition, status_sol=SOLUTION_STATUS_INFEASIBLE ) solution_dict = SuperDict() @@ -304,7 +303,4 @@ def solve(self, options): self.solution = Solution.from_dict(solution_dict) # self.plot_solution() - return dict( - status=termination_condition, - status_sol=SOLUTION_STATUS_FEASIBLE - ) + return dict(status=termination_condition, status_sol=SOLUTION_STATUS_FEASIBLE) diff --git a/cornflow-dags/DAG/update_all_schemas.py b/cornflow-dags/DAG/update_all_schemas.py index b9464791e..1ee819994 100644 --- a/cornflow-dags/DAG/update_all_schemas.py +++ b/cornflow-dags/DAG/update_all_schemas.py @@ -1,20 +1,15 @@ -# General imports import importlib as il import os import sys - -# Partial imports -from airflow.operators.python import PythonOperator -from airflow.models import Variable -from airflow import DAG -from airflow.utils.db import create_session from datetime import datetime, timedelta from typing import List -# Import from cornflow environment +from airflow import DAG +from airflow.models import Variable +from airflow.operators.python import PythonOperator +from airflow.utils.db import create_session from cornflow_client import ApplicationCore - default_args = { "owner": "baobab", "depends_on_past": False, diff --git a/cornflow-dags/DAG/update_dag_registry.py b/cornflow-dags/DAG/update_dag_registry.py index adc95ccda..909b4576d 100644 --- a/cornflow-dags/DAG/update_dag_registry.py +++ b/cornflow-dags/DAG/update_dag_registry.py @@ -1,15 +1,13 @@ -# Full imports - - # Partial imports +from datetime import datetime, timedelta + from airflow import DAG from airflow.models import DagModel from airflow.operators.python import PythonOperator from airflow.secrets.environment_variables import EnvironmentVariablesBackend from airflow.utils.db import create_session -from cornflow_client import CornFlow from cornflow_client.airflow.dag_utilities import connect_to_cornflow -from datetime import datetime, timedelta + from update_all_schemas import get_new_apps default_args = { @@ -27,7 +25,6 @@ def update_dag_registry(**kwargs): with create_session() as session: - model_dags = [ dag for dag in session.query(DagModel) diff --git a/cornflow-server/cornflow/cli/schemas.py b/cornflow-server/cornflow/cli/schemas.py index 5f523a217..3c24d7462 100644 --- a/cornflow-server/cornflow/cli/schemas.py +++ b/cornflow-server/cornflow/cli/schemas.py @@ -25,7 +25,7 @@ def schemas(): @schemas.command( name="generate_from_schema", - help="Command to generate models, endpoints and schemas from a jsonschema" + help="Command to generate models, endpoints and schemas from a jsonschema", ) @click.option( "--path", "-p", type=str, help="The absolute path to the JSONSchema", required=True @@ -70,7 +70,13 @@ def schemas(): required=False, ) def generate_from_schema( - path, app_name, output_path, remove_methods, one, endpoints_methods, endpoints_access + path, + app_name, + output_path, + remove_methods, + one, + endpoints_methods, + endpoints_access, ): """ This method is executed for the command and creates all the files for the REST API from the provided JSONSchema @@ -126,59 +132,64 @@ def generate_from_schema( output_path=output_path, options=methods_to_add, name_table=name_table, - endpoints_access=dict_endpoints_access + endpoints_access=dict_endpoints_access, ).main() -@schemas.command(name="schema_from_models", help="Command to generate a jsonschema from a set of models") -@click.option( - "--path", - "-p", - type=str, - help="The absolute path to folder containing the models", - required=True, -) -@click.option("--output-path", "-o", type=str, help="The output path", required=False) -@click.option( - "--ignore-files", - "-i", - type=str, - help="Files that will be ignored (with the .py extension). " - "__init__.py files are automatically ignored. Ex: 'instance.py'", - multiple=True, - required=False, -) -@click.option( - "--leave-bases/--no-leave-bases", - "-l/-nl", - default=False, - help="Use this option to leave the bases classes BaseDataModel, " - "EmptyModel and TraceAttributes in the schema. By default, they will be deleted", -) -def schema_from_models(path, output_path, ignore_files, leave_bases): - """ - - :param str path: the path to the folder that contains the models - :param output_path: the output path where the JSONSchema should be placed - :param str ignore_files: files to be ignored. - :param str leave_bases: if the JSONSchema should have abstract classes used as the base for other clases. - :return: a click status code - :rtype: int - """ - path = path.replace("\\", "/") - output = None - if output_path: - output = output_path.replace("\\", "/") - - if ignore_files: - ignore_files = list(ignore_files) - - click.echo("Generating JSONSchema file from the REST API") - click.echo(f"The path to the JSONSchema is {path}") - click.echo(f"The output_path is {output}") - click.echo(f"The ignore_files is {ignore_files}") - click.echo(f"The leave_bases is {leave_bases}") - - SchemaGenerator( - path, output_path=output, ignore_files=ignore_files, leave_bases=leave_bases - ).main() +# @schemas.command( +# name="schema_from_models", +# help="Command to generate a jsonschema from a set of models", +# ) +# @click.option( +# "--path", +# "-p", +# type=str, +# help="The absolute path to folder containing the models", +# required=True, +# ) +# @click.option("--output-path", "-o", type=str, help="The output path", required=False) +# @click.option( +# "--ignore-files", +# "-i", +# type=str, +# help="Files that will be ignored (with the .py extension). " +# "__init__.py files are automatically ignored. Ex: 'instance.py'", +# multiple=True, +# required=False, +# ) +# @click.option( +# "--leave-bases/--no-leave-bases", +# "-l/-nl", +# default=False, +# help="Use this option to leave the bases classes BaseDataModel, " +# "EmptyModel and TraceAttributes in the schema. By default, they will be deleted", +# ) +# def schema_from_models(path, output_path, ignore_files, leave_bases): +# """ +# +# :param str path: the path to the folder that contains the models +# :param output_path: the output path where the JSONSchema should be placed +# :param str ignore_files: files to be ignored. +# :param str leave_bases: if the JSONSchema should have abstract classes used as the base for other clases. +# :return: a click status code +# :rtype: int +# """ +# path = path.replace("\\", "/") +# output = None +# if output_path: +# output = output_path.replace("\\", "/") +# +# if ignore_files: +# ignore_files = list(ignore_files) +# +# click.echo("Generating JSONSchema file from the REST API") +# click.echo(f"The path to the JSONSchema is {path}") +# click.echo(f"The output_path is {output}") +# click.echo(f"The ignore_files is {ignore_files}") +# click.echo(f"The leave_bases is {leave_bases}") +# +# SchemaGenerator( +# path, output_path=output, ignore_files=ignore_files, leave_bases=leave_bases +# ).main() +# +# return True diff --git a/cornflow-server/cornflow/cli/tools/schema_generator.py b/cornflow-server/cornflow/cli/tools/schema_generator.py index a9cc3276a..890e840f0 100644 --- a/cornflow-server/cornflow/cli/tools/schema_generator.py +++ b/cornflow-server/cornflow/cli/tools/schema_generator.py @@ -6,6 +6,8 @@ import importlib.util from distutils.dir_util import copy_tree from unittest.mock import MagicMock + +import click from flask_sqlalchemy import SQLAlchemy import shutil from pytups import TupList, SuperDict @@ -15,7 +17,6 @@ class SchemaGenerator: def __init__(self, path, output_path=None, ignore_files=None, leave_bases=False): - self.path = path self.tmp_path = os.path.join(os.getcwd(), "tmp_files") self.output_path = output_path or "./output_schema.json" @@ -76,7 +77,6 @@ def parse(self, files): db = SQLAlchemy() try: for file_path, file_name in files: - spec = importlib.util.spec_from_file_location(file_name, file_path) mod = importlib.util.module_from_spec(spec) @@ -142,7 +142,7 @@ def parse(self, files): db.session.close() except Exception as err: - print(err) + click.echo(err) def inherit(self): all_classes = set(self.parents.keys()) diff --git a/cornflow-server/cornflow/endpoints/execution.py b/cornflow-server/cornflow/endpoints/execution.py index 8f6ddd7f4..579eb71dc 100644 --- a/cornflow-server/cornflow/endpoints/execution.py +++ b/cornflow-server/cornflow/endpoints/execution.py @@ -39,7 +39,11 @@ EXEC_STATE_QUEUED, ) from cornflow.shared.exceptions import AirflowError, ObjectDoesNotExist, InvalidData -from cornflow.shared.validators import json_schema_validate_as_string +from cornflow.shared.validators import ( + json_schema_validate_as_string, + json_schema_extend_and_validate_as_string, +) + class ExecutionEndpoint(BaseMetaResource): """ @@ -76,12 +80,10 @@ def get(self, **kwargs): ] running_executions = [ - execution for execution in executions - if execution.state in [ - EXEC_STATE_RUNNING, - EXEC_STATE_QUEUED, - EXEC_STATE_UNKNOWN - ] + execution + for execution in executions + if execution.state + in [EXEC_STATE_RUNNING, EXEC_STATE_QUEUED, EXEC_STATE_UNKNOWN] ] for execution in running_executions: @@ -146,14 +148,6 @@ def post(self, **kwargs): user=self.get_user(), idx=execution.instance_id ) - if instance is None: - err = "The instance to solve does not exist" - raise ObjectDoesNotExist( - error=err, - log_txt=f"Error while user {self.get_user()} tries to create an execution " - f"for instance {execution.instance_id}. " + err, - ) - current_app.logger.debug(f"The request is: {request.args.get('run')}") # this allows testing without airflow interaction: if request.args.get("run", "1") == "0": @@ -184,7 +178,9 @@ def post(self, **kwargs): # Validate config before running the dag config_schema = DeployedDAG.get_one_schema(config, schema, CONFIG_SCHEMA) - config_errors = json_schema_validate_as_string(config_schema, kwargs["config"]) + new_config, config_errors = json_schema_extend_and_validate_as_string( + config_schema, kwargs["config"] + ) if config_errors: execution.update_state( EXEC_STATE_ERROR_START, @@ -197,6 +193,8 @@ def post(self, **kwargs): log_txt=f"Error while user {self.get_user()} tries to create an execution. " f"Configuration data does not match the jsonschema.", ) + elif new_config != kwargs["config"]: + execution.update_config(new_config) # Validate instance data before running the dag instance_schema = DeployedDAG.get_one_schema(config, schema, INSTANCE_SCHEMA) @@ -326,7 +324,9 @@ def post(self, idx, **kwargs): }, 201 # Validate config before running the dag - config_schema = DeployedDAG.get_one_schema(config, kwargs["schema"], CONFIG_SCHEMA) + config_schema = DeployedDAG.get_one_schema( + config, kwargs["schema"], CONFIG_SCHEMA + ) config_errors = json_schema_validate_as_string(config_schema, kwargs["config"]) if config_errors: raise InvalidData( @@ -444,14 +444,18 @@ def put(self, idx, **data): schema = ExecutionModel.get_one_object(user=self.get_user(), idx=idx).schema if data.get("data") is not None and schema is not None: - data_jsonschema = DeployedDAG.get_one_schema(config, schema, SOLUTION_SCHEMA) - validation_errors = json_schema_validate_as_string(data_jsonschema, data["data"]) + data_jsonschema = DeployedDAG.get_one_schema( + config, schema, SOLUTION_SCHEMA + ) + validation_errors = json_schema_validate_as_string( + data_jsonschema, data["data"] + ) if validation_errors: raise InvalidData( payload=dict(jsonschema_errors=validation_errors), log_txt=f"Error while user {self.get_user()} tries to edit execution {idx}. " - f"Solution data does not match the jsonschema.", + f"Solution data does not match the jsonschema.", ) current_app.logger.info(f"User {self.get_user()} edits execution {idx}") diff --git a/cornflow-server/cornflow/models/dag.py b/cornflow-server/cornflow/models/dag.py index a45aeaf3d..40124c359 100644 --- a/cornflow-server/cornflow/models/dag.py +++ b/cornflow-server/cornflow/models/dag.py @@ -71,7 +71,8 @@ def get_one_schema(config, dag_name, schema=INSTANCE_SCHEMA): jsonschema = item.instance_checks_schema elif schema == SOLUTION_CHECKS_SCHEMA: jsonschema = item.solution_checks_schema - else: # schema == CONFIG_SCHEMA + # schema == CONFIG_SCHEMA + else: jsonschema = item.config_schema if jsonschema is None: diff --git a/cornflow-server/cornflow/models/execution.py b/cornflow-server/cornflow/models/execution.py index 680923ddf..fe17aa94e 100644 --- a/cornflow-server/cornflow/models/execution.py +++ b/cornflow-server/cornflow/models/execution.py @@ -99,6 +99,16 @@ def update(self, data): self.checks = None super().update(data) + def update_config(self, config: dict): + """ + Method to update the config of the execution after extending with default values + + :param dict config: The config to store + :return: nothing + """ + self.config = config + super().update({}) + def update_state(self, code, message=None): """ Method to update the state code and message of an execution diff --git a/cornflow-server/cornflow/shared/validators.py b/cornflow-server/cornflow/shared/validators.py index 49c6ae97d..550cb9de1 100644 --- a/cornflow-server/cornflow/shared/validators.py +++ b/cornflow-server/cornflow/shared/validators.py @@ -4,8 +4,9 @@ import re from typing import Tuple, Union -from jsonschema import Draft7Validator +from jsonschema import Draft7Validator, validators from disposable_email_domains import blocklist +from jsonschema.protocols import Validator def is_special_character(character): @@ -66,6 +67,27 @@ def check_email_pattern(email: str) -> Tuple[bool, Union[str, None]]: return True, None +def extend_with_default(validator_class): + """ + Method to extend a validator, so it extends the data with the default values defined on the jsonschema + """ + validate_properties = validator_class.VALIDATORS["properties"] + + def set_defaults(validator, properties, instance, schema): + for prop, sub in properties.items(): + if "default" in sub: + instance.setdefault(prop, sub["default"]) + for error in validate_properties( + validator, + properties, + instance, + schema, + ): + yield error + + return validators.extend(validator_class, {"properties": set_defaults}) + + def json_schema_validate(schema: dict, data: dict) -> list: """ Method to validate some data against a json schema @@ -81,6 +103,23 @@ def json_schema_validate(schema: dict, data: dict) -> list: return [] +def json_schema_extend_and_validate(schema: dict, data: dict) -> Tuple[dict, list]: + """ + Method to validate som data, extend it with default values and give back the processed errors + + :param dict schema: the json schema in dict format. + :param dict data: the data to validate in dict format + :return: a tuple with the data extended and the errors found + :rtype: tuple + """ + data_cp = dict(data) + default_validator = extend_with_default(Draft7Validator) + validator = default_validator(schema) + if not validator.is_valid(data_cp): + return data_cp, [e for e in validator.iter_errors(data_cp)] + return data_cp, [] + + def json_schema_validate_as_string(schema: dict, data: dict) -> list: """ Method to validate some data against a json schema @@ -91,3 +130,18 @@ def json_schema_validate_as_string(schema: dict, data: dict) -> list: :rtype: list """ return [str(e) for e in json_schema_validate(schema, data)] + + +def json_schema_extend_and_validate_as_string( + schema: dict, data: dict +) -> Tuple[dict, list]: + """ + Method to extend the schema with default values and give back the processed error + + :param dict schema: the json schema in dict format. + :param dict data: the data to validate in dict format + :return: a tuple with the data extended and the errors found + :rtype: tuple + """ + data_cp, errors = json_schema_extend_and_validate(schema, data) + return data_cp, [str(e) for e in errors] diff --git a/cornflow-server/cornflow/tests/const.py b/cornflow-server/cornflow/tests/const.py index 7063b589e..4f774b228 100644 --- a/cornflow-server/cornflow/tests/const.py +++ b/cornflow-server/cornflow/tests/const.py @@ -16,6 +16,8 @@ def _get_file(relative_path): INSTANCE_FILE_FAIL = _get_file("./unit/test_instances.py") EXECUTION_PATH = _get_file("./data/new_execution.json") +BAD_EXECUTION_PATH = _get_file("./data/bad_execution.json") +EXECUTION_SOLUTION_PATH = _get_file("./data/new_execution_solution.json") EXECUTIONS_LIST = [EXECUTION_PATH, _get_file("./data/new_execution_2.json")] EXECUTION_URL = PREFIX + "/execution/" EXECUTION_URL_NORUN = EXECUTION_URL + "?run=0" @@ -63,6 +65,8 @@ def _get_file(relative_path): ALARMS_URL = PREFIX + "/alarms/" MAIN_ALARMS_URL = PREFIX + "/main-alarms/" +LICENSES_URL = PREFIX + "/licences/" + PUBLIC_DAGS = [ "solve_model_dag", "gc", diff --git a/cornflow-server/cornflow/tests/data/bad_execution.json b/cornflow-server/cornflow/tests/data/bad_execution.json new file mode 100644 index 000000000..d18a303cb --- /dev/null +++ b/cornflow-server/cornflow/tests/data/bad_execution.json @@ -0,0 +1,19 @@ +{"config": { + "solver": 100, + "mip": true, + "msg": true, + "warmStart": true, + "timeLimit": 10, + "options": [""], + "keepFiles": 0, + "gapRel": 0.1, + "gapAbs": 1, + "maxMemory": 1000, + "maxNodes": 1, + "threads": 1, + "logPath": "test_export_solver_json.log" +}, +"name": "execution_1", +"description": "This is a test for the executions", +"schema": "solve_model_dag" +} diff --git a/cornflow-server/cornflow/tests/data/new_execution_solution.json b/cornflow-server/cornflow/tests/data/new_execution_solution.json new file mode 100644 index 000000000..1059cbb7c --- /dev/null +++ b/cornflow-server/cornflow/tests/data/new_execution_solution.json @@ -0,0 +1,123 @@ +{ + "objective": { + "name": "obj", + "coefficients": [ + { + "name": "x", + "value": 1 + }, + { + "name": "y", + "value": 4 + }, + { + "name": "z", + "value": 9 + } + ] + }, + "constraints": [ + { + "sense": -1, + "pi": null, + "constant": -5, + "name": "c1", + "coefficients": [ + { + "name": "x", + "value": 1 + }, + { + "name": "y", + "value": 1 + } + ] + }, + { + "sense": 1, + "pi": null, + "constant": -10, + "name": "c2", + "coefficients": [ + { + "name": "x", + "value": 1 + }, + { + "name": "z", + "value": 1 + } + ] + }, + { + "sense": 0, + "pi": null, + "constant": -7, + "name": "c3", + "coefficients": [ + { + "name": "y", + "value": -1 + }, + { + "name": "z", + "value": 1 + } + ] + }, + { + "sense": 1, + "pi": null, + "constant": 0, + "name": "c4", + "coefficients": [ + { + "name": "w", + "value": 1 + } + ] + } + ], + "variables": [ + { + "lowBound": 0, + "upBound": null, + "cat": "Continuous", + "varValue": 0, + "dj": null, + "name": "w" + }, + { + "lowBound": 0, + "upBound": 4, + "cat": "Continuous", + "varValue": 3, + "dj": null, + "name": "x" + }, + { + "lowBound": -1, + "upBound": 1, + "cat": "Continuous", + "varValue": 0, + "dj": null, + "name": "y" + }, + { + "lowBound": 0, + "upBound": null, + "cat": "Continuous", + "varValue": 7, + "dj": null, + "name": "z" + } + ], + "parameters": { + "name": "test_export_json_LP", + "sense": 1, + "status": 1, + "sol_status": 1 + }, + "sos1": [], + "sos2": [] +} diff --git a/cornflow-server/cornflow/tests/unit/test_executions.py b/cornflow-server/cornflow/tests/unit/test_executions.py index b9e175ebd..d7a94ee4c 100644 --- a/cornflow-server/cornflow/tests/unit/test_executions.py +++ b/cornflow-server/cornflow/tests/unit/test_executions.py @@ -16,6 +16,8 @@ EXECUTION_URL_NORUN, INSTANCE_URL, DAG_URL, + BAD_EXECUTION_PATH, + EXECUTION_SOLUTION_PATH, ) from cornflow.tests.custom_test_case import CustomTestCase, BaseTestCases from cornflow.tests.unit.tools import patch_af_client @@ -38,7 +40,9 @@ def load_file_fk(_file): return temp self.payload = load_file_fk(EXECUTION_PATH) + self.bad_payload = load_file_fk(BAD_EXECUTION_PATH) self.payloads = [load_file_fk(f) for f in EXECUTIONS_LIST] + self.solution = load_file_fk(EXECUTION_SOLUTION_PATH) def test_new_execution(self): self.create_new_row(self.url, self.model, payload=self.payload) @@ -49,6 +53,55 @@ def test_new_execution_run(self, af_client_class): self.create_new_row(EXECUTION_URL, self.model, payload=self.payload) + @patch("cornflow.endpoints.execution.Airflow") + def test_new_execution_bad_config(self, af_client_class): + patch_af_client(af_client_class) + response = self.create_new_row( + EXECUTION_URL, + self.model, + payload=self.bad_payload, + expected_status=400, + check_payload=False, + ) + self.assertIn("error", response) + self.assertIn("jsonschema_errors", response) + + @patch("cornflow.endpoints.execution.Airflow") + def test_new_execution_partial_config(self, af_client_class): + patch_af_client(af_client_class) + self.payload["config"].pop("solver") + response = self.create_new_row( + EXECUTION_URL, self.model, payload=self.payload, check_payload=False + ) + self.assertIn("solver", response["config"]) + self.assertEqual(response["config"]["solver"], "cbc") + + @patch("cornflow.endpoints.execution.Airflow") + def test_new_execution_with_solution(self, af_client_class): + patch_af_client(af_client_class) + self.payload["data"] = self.solution + response = self.create_new_row( + EXECUTION_URL, + self.model, + payload=self.payload, + check_payload=False, + ) + + @patch("cornflow.endpoints.execution.Airflow") + def test_new_execution_with_solution_bad(self, af_client_class): + patch_af_client(af_client_class) + patch_af_client(af_client_class) + self.payload["data"] = {"message": "THIS IS NOT A VALID SOLUTION"} + response = self.create_new_row( + EXECUTION_URL, + self.model, + payload=self.payload, + check_payload=False, + expected_status=400, + ) + self.assertIn("error", response) + self.assertIn("jsonschema_errors", response) + def test_new_execution_no_instance(self): payload = dict(self.payload) payload["instance_id"] = "bad_id" @@ -281,11 +334,7 @@ def test_update_one_row_data(self): def test_stop_execution(self, af_client_class): patch_af_client(af_client_class) - idx = self.create_new_row( - EXECUTION_URL, - self.model, - payload=self.payload - ) + idx = self.create_new_row(EXECUTION_URL, self.model, payload=self.payload) response = self.client.post( self.url + str(idx) + "/", @@ -347,11 +396,13 @@ def setUp(self): @patch("cornflow.endpoints.execution.Airflow") def test_get_one_status(self, af_client_class): patch_af_client(af_client_class) - + idx = self.create_new_row(EXECUTION_URL, self.model, self.payload) payload = dict(self.payload) payload["id"] = idx - data = self.get_one_row(EXECUTION_URL + idx + "/status/", payload, check_payload=False) + data = self.get_one_row( + EXECUTION_URL + idx + "/status/", payload, check_payload=False + ) self.assertEqual(data["state"], 1) @patch("cornflow.endpoints.execution.Airflow") diff --git a/cornflow-server/cornflow/tests/unit/test_licenses.py b/cornflow-server/cornflow/tests/unit/test_licenses.py new file mode 100644 index 000000000..c68743643 --- /dev/null +++ b/cornflow-server/cornflow/tests/unit/test_licenses.py @@ -0,0 +1,45 @@ +from cornflow.endpoints import LicensesEndpoint +from cornflow.tests.const import LICENSES_URL, _get_file +from cornflow.tests.custom_test_case import CustomTestCase + + +class TestLicensesListEndpoint(CustomTestCase): + @staticmethod + def read_requirements(): + with open(_get_file("../../requirements.txt")) as req: + content = req.read() + requirements = content.split("\n") + + requirements = [ + r.split("=")[0].split(">")[0].split("<")[0].lower() + for r in requirements + if r != "" + ] + return requirements + + def setUp(self): + super().setUp() + self.roles_with_access = LicensesEndpoint.ROLES_WITH_ACCESS + self.libraries = self.read_requirements() + + def tearDown(self): + super().tearDown() + + def test_get_licenses(self): + for role in self.roles_with_access: + self.token = self.create_user_with_role(role) + response = self.client.get( + LICENSES_URL, + follow_redirects=True, + headers={ + "Content-Type": "application/json", + "Authorization": "Bearer " + self.token, + }, + ) + + self.assertEqual(200, response.status_code) + self.assertIsInstance(response.json, list) + libraries = [k["library"].lower() for k in response.json] + + for lib in self.libraries: + self.assertIn(lib, libraries) diff --git a/cornflow-server/cornflow/tests/unit/test_schema_from_models.py b/cornflow-server/cornflow/tests/unit/test_schema_from_models.py index 8e39ab04c..e91d7dd2a 100644 --- a/cornflow-server/cornflow/tests/unit/test_schema_from_models.py +++ b/cornflow-server/cornflow/tests/unit/test_schema_from_models.py @@ -1,124 +1,135 @@ -import unittest -import json -import os - -from click.testing import CliRunner - -from cornflow.cli import cli - -path_to_tests = os.path.dirname(os.path.abspath(__file__)) - - -class SchemaFromModelsTests(unittest.TestCase): - def setUp(self): - super().setUp() - self.models_path = self._get_path("../data/models") - self.output_path = self._get_path(os.path.join(os.getcwd(), "test_output.json")) - - @staticmethod - def import_schema(path): - with open(path, "r") as fd: - schema = json.load(fd) - return schema - - @staticmethod - def _get_path(rel_path): - return os.path.join(path_to_tests, rel_path) - - def tearDown(self): - if os.path.exists(self.output_path): - os.remove(self.output_path) - - def test_base(self): - runner = CliRunner() - result = runner.invoke( - cli, - [ - "schemas", - "schema_from_models", - "-p", - self.models_path, - "-o", - self.output_path - ] - ) - - self.assertEqual(result.exit_code, 0) - - schema = self.import_schema(self._get_path(self.output_path)) - - tables = { - "instances": { - "id": "string", - "data": "object", - "checks": "object", - "name": "string", - "description": "string", - }, - "actions": {"id": "integer", "name": "string"}, - "permission_dag": { - "id": "integer", - "dag_id": "string", - "user_id": "integer", - }, - "permission_view": { - "id": "integer", - "action_id": "integer", - "api_view_id": "integer", - "role_id": "integer", - }, - } - required_instance = {"id", "name", "data_hash"} - foreign_keys = [ - ("permission_dag", "dag_id", "deployed_dags.id"), - ("permission_dag", "user_id", "users.id"), - ("permission_view", "action_id", "actions.id"), - ("permission_view", "api_view_id", "api_view.id"), - ] - for tab_name, tab_checks in tables.items(): - # All tables exist - self.assertIn(tab_name, schema["properties"]) - # The properties have correct types - for prop, type_prop in tab_checks.items(): - table_props = schema["properties"][tab_name]["items"]["properties"] - self.assertIn(prop, table_props) - self.assertIn("type", table_props.get(prop, {}).keys()) - self.assertEqual( - type_prop, table_props.get(prop, {}).get("type", "null") - ) - # The foreign keys are correct - for tab, key, foreign_key in foreign_keys: - self.assertIn( - "foreign_key", schema["properties"][tab]["items"]["properties"][key] - ) - self.assertEqual( - schema["properties"][tab]["items"]["properties"][key]["foreign_key"], - foreign_key, - ) - # The required property is correct - self.assertEqual( - required_instance, - set(schema["properties"]["instances"]["items"]["required"]), - ) - - def test_ignore(self): - runner = CliRunner() - result = runner.invoke( - cli, - [ - "schemas", - "schema_from_models", - "-p", - self.models_path, - "-o", - self.output_path, - "-i", - "instance.py" - ] - ) - - self.assertEqual(result.exit_code, 0) - - schema = self.import_schema(self.output_path) - - self.assertNotIn("instances", schema["properties"].keys()) +# import json +# import os +# import unittest +# +# from click.testing import CliRunner +# from flask_testing import TestCase +# +# from cornflow.app import create_app +# from cornflow.cli import cli +# from cornflow.shared import db +# +# path_to_tests = os.path.dirname(os.path.abspath(__file__)) +# +# +# class SchemaFromModelsTests(TestCase): +# def create_app(self): +# app = create_app("testing") +# return app +# +# def setUp(self): +# db.create_all() +# self.models_path = self._get_path("../../models") +# print(self.models_path) +# self.output_path = self._get_path(os.path.join(os.getcwd(), "test_output.json")) +# print(self.output_path) +# +# @staticmethod +# def import_schema(path): +# with open(path, "r") as fd: +# schema = json.load(fd) +# return schema +# +# @staticmethod +# def _get_path(rel_path): +# return os.path.join(path_to_tests, rel_path) +# +# def tearDown(self): +# db.session.remove() +# db.drop_all() +# if os.path.exists(self.output_path): +# os.remove(self.output_path) +# +# def test_base(self): +# runner = CliRunner() +# result = runner.invoke( +# cli, +# [ +# "schemas", +# "schema_from_models", +# "-p", +# self.models_path, +# "-o", +# self.output_path, +# ], +# ) +# +# self.assertEqual(result.exit_code, True) +# +# schema = self.import_schema(self._get_path(self.output_path)) +# +# tables = { +# "instances": { +# "id": "string", +# "data": "object", +# "checks": "object", +# "name": "string", +# "description": "string", +# }, +# "actions": {"id": "integer", "name": "string"}, +# "permission_dag": { +# "id": "integer", +# "dag_id": "string", +# "user_id": "integer", +# }, +# "permission_view": { +# "id": "integer", +# "action_id": "integer", +# "api_view_id": "integer", +# "role_id": "integer", +# }, +# } +# required_instance = {"id", "name", "data_hash"} +# foreign_keys = [ +# ("permission_dag", "dag_id", "deployed_dags.id"), +# ("permission_dag", "user_id", "users.id"), +# ("permission_view", "action_id", "actions.id"), +# ("permission_view", "api_view_id", "api_view.id"), +# ] +# for tab_name, tab_checks in tables.items(): +# # All tables exist +# self.assertIn(tab_name, schema["properties"]) +# # The properties have correct types +# for prop, type_prop in tab_checks.items(): +# table_props = schema["properties"][tab_name]["items"]["properties"] +# self.assertIn(prop, table_props) +# self.assertIn("type", table_props.get(prop, {}).keys()) +# self.assertEqual( +# type_prop, table_props.get(prop, {}).get("type", "null") +# ) +# # The foreign keys are correct +# for tab, key, foreign_key in foreign_keys: +# self.assertIn( +# "foreign_key", schema["properties"][tab]["items"]["properties"][key] +# ) +# self.assertEqual( +# schema["properties"][tab]["items"]["properties"][key]["foreign_key"], +# foreign_key, +# ) +# # The required property is correct +# self.assertEqual( +# required_instance, +# set(schema["properties"]["instances"]["items"]["required"]), +# ) +# +# def test_ignore(self): +# runner = CliRunner() +# result = runner.invoke( +# cli, +# [ +# "schemas", +# "schema_from_models", +# "-p", +# self.models_path, +# "-o", +# self.output_path, +# "-i", +# "instance.py", +# ], +# ) +# +# self.assertEqual(result.exit_code, True) +# +# schema = self.import_schema(self.output_path) +# +# self.assertNotIn("instances", schema["properties"].keys()) diff --git a/libs/client/cornflow_client/airflow/dag_utilities.py b/libs/client/cornflow_client/airflow/dag_utilities.py index 8cdb69814..6e5a4ae5f 100644 --- a/libs/client/cornflow_client/airflow/dag_utilities.py +++ b/libs/client/cornflow_client/airflow/dag_utilities.py @@ -318,9 +318,10 @@ def callback_email(context): from airflow.secrets.environment_variables import EnvironmentVariablesBackend path_to_log = ( - f"./logs/{context['dag'].dag_id}/" - f"{context['ti'].task_id}/{context['ts']}/1.log" + f"./logs/dag_id={context['dag'].dag_id}/run_id={context['run_id']}" + f"/task_id={context['ti'].task_id}/attempt=1.log" ) + environment = EnvironmentVariablesBackend().get_variable("ENVIRONMENT") notification_email = EnvironmentVariablesBackend().get_variable( "NOTIFICATION_EMAIL" From 6ff8debccc7f6570aadb8bdfcc988c12b9e8c0c8 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Tue, 10 Oct 2023 17:32:49 +0200 Subject: [PATCH 10/22] Bump version codes --- cornflow-dags/requirements.txt | 2 +- cornflow-server/Dockerfile | 4 ++-- cornflow-server/changelog.rst | 5 +++++ cornflow-server/requirements.txt | 2 +- cornflow-server/setup.py | 2 +- libs/client/changelog.rst | 9 +++++++++ libs/client/setup.py | 2 +- 7 files changed, 20 insertions(+), 6 deletions(-) diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 1c0105fd1..d5fa1917c 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,4 +1,4 @@ -cornflow-client<=1.0.15 +cornflow-client==1.0.16a1 orloge<=0.17.2 PuLP<=2.7 pandas<=2.1.1 diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index 6520f93cb..6ee4637c3 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -1,4 +1,4 @@ -# VERSION 2.0.2 +# VERSION 1.0.8a1 # AUTHOR: sistemas@baobabsoluciones.es FROM python:3.10-slim-buster @@ -9,7 +9,7 @@ ENV DEBIAN_FRONTEND noninteractive ENV TERM linux # CORNFLOW vars -ARG CORNFLOW_VERSION=1.0.7 +ARG CORNFLOW_VERSION=1.0.8a1 # install linux pkg RUN apt update -y && apt-get install -y --no-install-recommends \ diff --git a/cornflow-server/changelog.rst b/cornflow-server/changelog.rst index b799408e4..15f7e6857 100644 --- a/cornflow-server/changelog.rst +++ b/cornflow-server/changelog.rst @@ -1,3 +1,8 @@ +version 1.0.8 +-------------- + + + version 1.0.7 -------------- diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index e2d6fcefe..0e646c117 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -1,7 +1,7 @@ alembic==1.9.2 apispec<=6.2.0 click<=8.1.3 -cornflow-client<=1.0.14 +cornflow-client==1.0.16a1 cryptography<=39.0.2 disposable-email-domains>=0.0.86 Flask==2.3.2 diff --git a/cornflow-server/setup.py b/cornflow-server/setup.py index 88ed3a1a9..469f0d645 100644 --- a/cornflow-server/setup.py +++ b/cornflow-server/setup.py @@ -9,7 +9,7 @@ setuptools.setup( name="cornflow", - version="1.0.7", + version="1.0.8a1", author="baobab soluciones", author_email="cornflow@baobabsoluciones.es", description="Cornflow is an open source multi-solver optimization server with a REST API built using flask.", diff --git a/libs/client/changelog.rst b/libs/client/changelog.rst index 1f8571d94..e7828d0bc 100644 --- a/libs/client/changelog.rst +++ b/libs/client/changelog.rst @@ -1,3 +1,12 @@ +version 1.0.16 +--------------- + + +version 1.0.15 +--------------- + + + version 1.0.14 --------------- diff --git a/libs/client/setup.py b/libs/client/setup.py index bb72b26bc..e5ffcc364 100644 --- a/libs/client/setup.py +++ b/libs/client/setup.py @@ -12,7 +12,7 @@ setuptools.setup( name="cornflow-client", - version="1.0.15", + version="1.0.16a1", author="baobab soluciones", author_email="sistemas@baobabsoluciones.es", description="Client to connect to a cornflow server", From 0c5ade32c0edd3a360194c5a170eed49c11ef4e5 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 13 Oct 2023 11:05:25 +0200 Subject: [PATCH 11/22] Change on requiremtents.txt --- libs/client/requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/client/requirements.txt b/libs/client/requirements.txt index 38f84b9fc..dbbe3ff88 100644 --- a/libs/client/requirements.txt +++ b/libs/client/requirements.txt @@ -1,8 +1,8 @@ -requests +requests==2.31.0 genson jsonschema -marshmallow -pytups +marshmallow<=3.19.0 +pytups>=0.86.2 ortools pandas>=1.5.2 PuLP>=2.3 \ No newline at end of file From 36345fadbbbaf75dbbe34d577a41768a78eae82d Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 13 Oct 2023 11:09:34 +0200 Subject: [PATCH 12/22] Bump cornflow version --- cornflow-server/Dockerfile | 2 +- cornflow-server/setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index 6ee4637c3..c655aff9d 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -9,7 +9,7 @@ ENV DEBIAN_FRONTEND noninteractive ENV TERM linux # CORNFLOW vars -ARG CORNFLOW_VERSION=1.0.8a1 +ARG CORNFLOW_VERSION=1.0.8a2 # install linux pkg RUN apt update -y && apt-get install -y --no-install-recommends \ diff --git a/cornflow-server/setup.py b/cornflow-server/setup.py index 469f0d645..a6ca656a0 100644 --- a/cornflow-server/setup.py +++ b/cornflow-server/setup.py @@ -9,7 +9,7 @@ setuptools.setup( name="cornflow", - version="1.0.8a1", + version="1.0.8a2", author="baobab soluciones", author_email="cornflow@baobabsoluciones.es", description="Cornflow is an open source multi-solver optimization server with a REST API built using flask.", From 98824b1a5e9af1cc684cc4de4877cf75131102f3 Mon Sep 17 00:00:00 2001 From: dag Date: Fri, 13 Oct 2023 13:28:01 +0200 Subject: [PATCH 13/22] Feature/deploy changes (#482) * gurobi10 and yml changes * ldap compose deployment changes * fix cornflow exposed port * config custom Airflow UI for CornflowEnv * new dashboard alert to welcome users --------- Co-authored-by: Guillermo Gonzalez-Santander --- .gitignore | 5 +- cornflow-server/Dockerfile | 7 +- cornflow-server/airflow_config/Dockerfile | 4 +- .../airflow_config/airflow_local_settings.py | 23 ++ .../airflow_config/logs/README.rst | 10 + .../scripts/solvers/get_gurobi.py | 6 +- docker-compose-cornflow-celery.yml | 264 +++++++++++------- docker-compose-cornflow-ldap.yml | 181 ++++++++---- docker-compose.yml | 165 +++++++---- 9 files changed, 467 insertions(+), 198 deletions(-) create mode 100644 cornflow-server/airflow_config/airflow_local_settings.py create mode 100644 cornflow-server/airflow_config/logs/README.rst diff --git a/.gitignore b/.gitignore index fd7086dce..584d2d0f5 100644 --- a/.gitignore +++ b/.gitignore @@ -169,4 +169,7 @@ cornssh.pub *.db # IO files -*.mps \ No newline at end of file +*.mps + +# airflow logs +cornflow-server/airflow_config/logs \ No newline at end of file diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index 6520f93cb..e9bb2b221 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -2,7 +2,7 @@ # AUTHOR: sistemas@baobabsoluciones.es FROM python:3.10-slim-buster -LABEL maintainer="sistemas@baobabsoluciones" +LABEL maintainer="cornflow@baobabsoluciones" # Never prompt the user for choices on installation/configuration of packages ENV DEBIAN_FRONTEND noninteractive @@ -39,6 +39,11 @@ RUN mkdir -p /usr/src/app/log # create folder for custom ssh keys RUN mkdir /usr/src/app/.ssh +# user cornflow on application +RUN useradd -ms /bin/bash -d /usr/src/app cornflow +RUN chown -R cornflow: /usr/src/app +USER cornflow + EXPOSE 5000 # execute python init script diff --git a/cornflow-server/airflow_config/Dockerfile b/cornflow-server/airflow_config/Dockerfile index e4b1ad305..44239dcba 100644 --- a/cornflow-server/airflow_config/Dockerfile +++ b/cornflow-server/airflow_config/Dockerfile @@ -1,9 +1,9 @@ # VERSION 2.7.1 -# AUTHOR: sistemas@baobabsoluciones.es +# AUTHOR: cornflow@baobabsoluciones.es # DESCRIPTION: Airflow 2.7.1 image personalized for use with Cornflow (from puckel/docker-airflow https://github.com/puckel/docker-airflow by "Puckel_") FROM python:3.10-slim-buster -LABEL maintainer="sistemas@baobabsoluciones" +LABEL maintainer="cornflow@baobabsoluciones" # Never prompt the user for choices on installation/configuration of packages ENV DEBIAN_FRONTEND noninteractive diff --git a/cornflow-server/airflow_config/airflow_local_settings.py b/cornflow-server/airflow_config/airflow_local_settings.py new file mode 100644 index 000000000..daa7c99e4 --- /dev/null +++ b/cornflow-server/airflow_config/airflow_local_settings.py @@ -0,0 +1,23 @@ +# AIRFLOW custom UI colors for CornflowEnv + +STATE_COLORS = { + "deferred": "#7c4fe0", + "failed": "#c9301c", + "queued": "#656d78", + "removed": "#7bdcb5", + "restarting": "#9b51e0", + "running": "#01FF70", + "scheduled": "#fcb900", + "shutdown": "blue", + "skipped": "darkorchid", + "success": "#00d084", + "up_for_reschedule": "#f78da7", + "up_for_retry": "yellow", + "upstream_failed": "#b31e1e", +} + +from airflow.www.utils import UIAlert + +DASHBOARD_UIALERTS = [ + UIAlert("Welcome! This is the backend of your Cornflow environment. Airflow™ is a platform created by the community to programmatically author, schedule and monitor workflows."), +] \ No newline at end of file diff --git a/cornflow-server/airflow_config/logs/README.rst b/cornflow-server/airflow_config/logs/README.rst new file mode 100644 index 000000000..b61608dfa --- /dev/null +++ b/cornflow-server/airflow_config/logs/README.rst @@ -0,0 +1,10 @@ +Airflow LOGS +-------------- + +Users can specify the directory to place log files in airflow.cfg using base_log_folder. By default, logs are placed in the AIRFLOW_HOME directory. + +The following convention is followed while naming logs: {dag_id}/{task_id}/{execution_date}/{try_number}.log + +In addition, users can supply a remote location to store current logs and backups. + +In the Airflow Web UI, local logs take precedence over remote logs. If local logs can not be found or accessed, the remote logs will be displayed. Note that logs are only sent to remote storage once a task is complete (including failure); In other words, remote logs for running tasks are unavailable. \ No newline at end of file diff --git a/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py b/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py index 7b22e413d..522cb4f43 100644 --- a/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py +++ b/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py @@ -22,10 +22,10 @@ def install(): install_dir = "/usr/local/airflow/gurobi" os.chdir("/usr/local/airflow") subprocess.check_output( - ["wget", "https://packages.gurobi.com/9.5/gurobi9.5.0_linux64.tar.gz"] + ["wget", "https://packages.gurobi.com/10.0/gurobi10.0.1_linux64.tar.gz"] ) - subprocess.check_output(["tar", "-xvf", "gurobi9.5.0_linux64.tar.gz"]) - os.rename("gurobi950", "gurobi") + subprocess.check_output(["tar", "-xvf", "gurobi10.0.1_linux64.tar.gz"]) + os.rename("gurobi1001", "gurobi") uid = pwd.getpwnam("airflow").pw_uid gid = grp.getgrnam("airflow").gr_gid os.chown(install_dir, uid, gid) diff --git a/docker-compose-cornflow-celery.yml b/docker-compose-cornflow-celery.yml index ee6ec2681..8e530ef44 100644 --- a/docker-compose-cornflow-celery.yml +++ b/docker-compose-cornflow-celery.yml @@ -1,136 +1,212 @@ -version: '3' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Basic Airflow cluster configuration for CeleryExecutor with Redis and PostgreSQL. +# +# WARNING: This configuration is for local development. Do not use it in a production deployment. +# +# This configuration supports basic configuration using environment variables or an .env file +# The following variables are supported: +# +# Feel free to modify this file to suit your needs. +version: '3.8' + +x-airflow-common: + &airflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/airflow:latest + platform: linux/amd64 + #build: + #context: ./cornflow-server/airflow_config + environment: + &airflow-common-env + AIRFLOW_USER: admin + AIRFLOW_PWD: admin + AIRFLOW_DB_HOST: airflow_db + AIRFLOW_DB_PORT: 5432 + AIRFLOW_DB_USER: airflow + AIRFLOW_DB_PASSWORD: airflow + AIRFLOW_DB: airflow + AIRFLOW__CORE__FERNET_KEY: '' + EXECUTOR: Celery + AIRFLOW__WEBSERVER__INSTANCE_NAME: CornflowEnv + AIRFLOW__WEBSERVER__NAVBAR_COLOR: '#0693e3' + volumes: + - ./cornflow-dags/DAG:/usr/local/airflow/dags + - ./cornflow-dags/requirements.txt:/requirements.txt + - ./cornflow-server/airflow_config/logs:/usr/local/airflow/logs + - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins + - ./cornflow-server/airflow_config/airflow_local_settings.py:/usr/local/airflow/config/airflow_local_settings.py + depends_on: + &airflow-common-depends-on + redis: + condition: service_healthy + airflow_db: + condition: service_healthy + +x-cornflow-common: + &cornflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/cornflow:release-v1.0.7 + platform: linux/amd64 + #build: + #context: ./cornflow-server + environment: + &cornflow-common-env + CORNFLOW_ADMIN_USER: cornflow_admin + CORNFLOW_ADMIN_PWD: Cornflow_admin1234 + CORNFLOW_SERVICE_USER: service_user + CORNFLOW_SERVICE_PWD: Service_user1234 + CORNFLOW_DB_HOST: cornflow_db + CORNFLOW_DB_PORT: 5432 + CORNFLOW_DB_USER: cornflow + CORNFLOW_DB_PASSWORD: cornflow + CORNFLOW_DB: cornflow + depends_on: + &cornflow-common-depends-on + cornflow_db: + condition: service_healthy + webserver: + condition: service_healthy services: cornflow: - build: - context: ./cornflow-server - dockerfile: Dockerfile + <<: *cornflow-common restart: always ports: - 5000:5000 + healthcheck: + test: ["CMD-SHELL", "[ -f /usr/src/app/gunicorn.pid ]"] + interval: 30s + timeout: 30s + retries: 5 environment: - - CORNFLOW_ADMIN_USER=cornflow_admin - - CORNFLOW_ADMIN_PWD=Cornflow_admin1234 - - CORNFLOW_SERVICE_USER=service_user - - CORNFLOW_SERVICE_PWD=Service_user1234 - - CORNFLOW_DB_HOST=cornflow_db - - CORNFLOW_DB_PORT=5432 - - CORNFLOW_DB_USER=cornflow - - CORNFLOW_DB_PASSWORD=cornflow - - CORNFLOW_DB=cornflow + <<: *cornflow-common-env depends_on: - - cornflow_db - - webserver + <<: *cornflow-common-depends-on cornflow_db: - image: postgres + image: postgres:15.4 environment: - POSTGRES_USER=cornflow - POSTGRES_PASSWORD=cornflow - POSTGRES_DB=cornflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "cornflow"] + interval: 10s + retries: 5 + start_period: 5s + restart: always volumes: - postgres_cf_data:/var/lib/postgresql/data/ + + airflow_db: + image: postgres:15.4 + environment: + - POSTGRES_USER=airflow + - POSTGRES_PASSWORD=airflow + - POSTGRES_DB=airflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "airflow"] + interval: 10s + retries: 5 + start_period: 5s + volumes: + - postgres_af_data:/var/lib/postgresql/data/ webserver: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile - restart: always - volumes: - - ./cornflow-dags/DAG:/usr/local/airflow/dags - - ./cornflow-dags/requirements.txt:/requirements.txt - - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins - environment: - - AIRFLOW_USER=admin - - AIRFLOW_PWD=admin - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_PORT=5432 - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - AIRFLOW_DB=airflow - - AIRFLOW__CORE__FERNET_KEY=L5Z7WRVv5zaexK0OL3pS2stYUF-gx_UmfDBqWQ4br6Y= - - EXECUTOR=Celery + <<: *airflow-common + command: webserver ports: - 8080:8080 - depends_on: - - airflow_db - - redis - command: webserver healthcheck: test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"] interval: 30s timeout: 30s retries: 5 + environment: + <<: *airflow-common-env + restart: always + depends_on: + <<: *airflow-common-depends-on scheduler: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile + <<: *airflow-common + command: scheduler + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:8974/health"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + environment: + <<: *airflow-common-env restart: always depends_on: - - webserver - volumes: - - ./cornflow-dags/DAG:/usr/local/airflow/dags - - ./cornflow-dags/requirements.txt:/requirements.txt - - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins - environment: - - AIRFLOW_USER=admin - - AIRFLOW_PWD=admin - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_PORT=5432 - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - AIRFLOW_DB=airflow - - AIRFLOW__CORE__FERNET_KEY=L5Z7WRVv5zaexK0OL3pS2stYUF-gx_UmfDBqWQ4br6Y= - - EXECUTOR=Celery - command: scheduler + <<: *airflow-common-depends-on + # You can enable flower by adding "--profile flower" option e.g. docker-compose --profile flower up + # or by explicitly targeted on the command line e.g. docker-compose up flower. + # See: https://docs.docker.com/compose/profiles/ flower: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile - restart: always - depends_on: - - redis - environment: - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - EXECUTOR=Celery - ports: - - "5555:5555" + <<: *airflow-common command: flower - - airflow_db: - image: postgres + profiles: + - flower + ports: + - "5555:5555" + healthcheck: + test: ["CMD", "curl", "--fail", "http://localhost:5555/"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s environment: - - POSTGRES_USER=airflow - - POSTGRES_PASSWORD=airflow - - POSTGRES_DB=airflow - volumes: - - postgres_af_data:/var/lib/postgresql/data/ + <<: *airflow-common-env + restart: always + depends_on: + <<: *airflow-common-depends-on redis: - image: redis:5.0.5 + image: redis:latest + expose: + - 6379 + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 30s + retries: 50 + start_period: 30s + restart: always worker: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile + <<: *airflow-common + command: worker + environment: + <<: *airflow-common-env + # Required to handle warm shutdown of the celery workers properly + # See https://airflow.apache.org/docs/docker-stack/entrypoint.html#signal-propagation + DUMB_INIT_SETSID: "0" restart: always depends_on: - - scheduler - volumes: - - ./cornflow-dags/DAG:/usr/local/airflow/dags - - ./cornflow-dags/requirements.txt:/requirements.txt - - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins - environment: - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - AIRFLOW__CORE__FERNET_KEY=L5Z7WRVv5zaexK0OL3pS2stYUF-gx_UmfDBqWQ4br6Y= - - EXECUTOR=Celery - command: worker + <<: *airflow-common-depends-on volumes: postgres_cf_data: diff --git a/docker-compose-cornflow-ldap.yml b/docker-compose-cornflow-ldap.yml index 79735357e..4457dd588 100644 --- a/docker-compose-cornflow-ldap.yml +++ b/docker-compose-cornflow-ldap.yml @@ -1,79 +1,160 @@ -version: '3' + +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Basic Airflow cluster configuration for development purposes with LDAP Auth. +# +# WARNING: This configuration is for local development. Do not use it in a production deployment. +# +# This configuration supports basic configuration using environment variables or an .env file +# The following variables are supported: +# +# Feel free to modify this file to suit your needs. +version: '3.8' + +x-airflow-common: + &airflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/airflow:latest + platform: linux/amd64 + #build: + #context: ./cornflow-server/airflow_config + environment: + &airflow-common-env + AIRFLOW_DB_HOST: airflow_db + AIRFLOW_DB_PORT: 5432 + AIRFLOW_DB_USER: airflow + AIRFLOW_DB_PASSWORD: airflow + AIRFLOW_DB: airflow + AIRFLOW__WEBSERVER__INSTANCE_NAME: CornflowEnv + AIRFLOW__WEBSERVER__NAVBAR_COLOR: '#0693e3' + AIRFLOW_LDAP_ENABLE: 'True' + AIRFLOW_LDAP_URI: ldap://openldap:389 + AIRFLOW_LDAP_SEARCH: ou=users,dc=example,dc=org + AIRFLOW_LDAP_BIND_USER: cn=admin,dc=example,dc=org + AIRFLOW_LDAP_BIND_PASSWORD: admin + AIRFLOW_LDAP_UID_FIELD: cn + # cornflow user and password from LDAP credentials file in cornflow-server/airflow_config/ldapbootstrap.ldif + CORNFLOW_SERVICE_USER: cornflow + CORNFLOW_SERVICE_PWD: cornflow1234 + volumes: + - ./cornflow-dags/DAG:/usr/local/airflow/dags + - ./cornflow-dags/requirements.txt:/requirements.txt + - ./cornflow-server/airflow_config/logs:/usr/local/airflow/logs + - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins + - ./cornflow-server/airflow_config/airflow_local_settings.py:/usr/local/airflow/config/airflow_local_settings.py + depends_on: + &airflow-common-depends-on + airflow_db: + condition: service_healthy + +x-cornflow-common: + &cornflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/cornflow:release-v1.0.7 + platform: linux/amd64 + #build: + #context: ./cornflow-server + environment: + &cornflow-common-env + CORNFLOW_DB_HOST: cornflow_db + CORNFLOW_DB_PORT: 5432 + CORNFLOW_DB_USER: cornflow + CORNFLOW_DB_PASSWORD: cornflow + CORNFLOW_DB: cornflow + AUTH_TYPE: 2 + LDAP_HOST: ldap://openldap:389 + LDAP_BIND_DN: cn=admin,dc=example,dc=org + LDAP_BIND_PASSWORD: admin + LDAP_SERVICE_BASE: ou=service,dc=example,dc=org + CORNFLOW_SERVICE_USER: cornflow + # airflow user and password from LDAP credentials file in cornflow-server/airflow_config/ldapbootstrap.ldif + AIRFLOW_USER: administrator + AIRFLOW_PWD: administrator1234 + depends_on: + &cornflow-common-depends-on + cornflow_db: + condition: service_healthy + webserver: + condition: service_healthy services: cornflow: - build: - context: ./cornflow-server - dockerfile: Dockerfile + <<: *cornflow-common restart: always ports: - 5000:5000 + healthcheck: + test: ["CMD-SHELL", "[ -f /usr/src/app/gunicorn.pid ]"] + interval: 30s + timeout: 30s + retries: 5 environment: - - CORNFLOW_DB_HOST=cornflow_db - - CORNFLOW_DB_PORT=5432 - - CORNFLOW_DB_USER=cornflow - - CORNFLOW_DB_PASSWORD=cornflow - - CORNFLOW_DB=cornflow - - AUTH_TYPE=2 - - LDAP_HOST=ldap://openldap:389 - - LDAP_BIND_DN=cn=admin,dc=example,dc=org - - LDAP_BIND_PASSWORD=admin - - LDAP_SERVICE_BASE=ou=service,dc=example,dc=org - - CORNFLOW_SERVICE_USER=cornflow + <<: *cornflow-common-env depends_on: - - cornflow_db - - webserver + <<: *cornflow-common-depends-on cornflow_db: - image: postgres + image: postgres:15.4 environment: - POSTGRES_USER=cornflow - POSTGRES_PASSWORD=cornflow - POSTGRES_DB=cornflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "cornflow"] + interval: 10s + retries: 5 + start_period: 5s + restart: always volumes: - postgres_cf_data:/var/lib/postgresql/data/ + + airflow_db: + image: postgres:15.4 + environment: + - POSTGRES_USER=airflow + - POSTGRES_PASSWORD=airflow + - POSTGRES_DB=airflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "airflow"] + interval: 10s + retries: 5 + start_period: 5s + volumes: + - postgres_af_data:/var/lib/postgresql/data/ webserver: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile - restart: always - volumes: - - ./cornflow-dags/DAG:/usr/local/airflow/dags - - ./cornflow-dags/requirements.txt:/requirements.txt - - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins - environment: - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_PORT=5432 - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - AIRFLOW_DB=airflow - - AIRFLOW_LDAP_ENABLE=True - - AIRFLOW_LDAP_URI=ldap://openldap:389 - - AIRFLOW_LDAP_SEARCH=ou=users,dc=example,dc=org - - AIRFLOW_LDAP_BIND_USER=cn=admin,dc=example,dc=org - - AIRFLOW_LDAP_BIND_PASSWORD=admin - - AIRFLOW_LDAP_UID_FIELD=cn + <<: *airflow-common + command: webserver ports: - 8080:8080 - depends_on: - - airflow_db - - openldap - command: webserver healthcheck: test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"] interval: 30s timeout: 30s retries: 5 - - airflow_db: - image: postgres environment: - - POSTGRES_USER=airflow - - POSTGRES_PASSWORD=airflow - - POSTGRES_DB=airflow - volumes: - - postgres_af_data:/var/lib/postgresql/data/ + <<: *airflow-common-env + restart: always + depends_on: + <<: *airflow-common-depends-on openldap: image: osixia/openldap diff --git a/docker-compose.yml b/docker-compose.yml index 2b4c99695..9308d8226 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,77 +1,148 @@ -version: '3' +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +# Basic Airflow cluster configuration for development purposes. +# +# WARNING: This configuration is for local development. Do not use it in a production deployment. +# +# This configuration supports basic configuration using environment variables or an .env file +# The following variables are supported: +# +# Feel free to modify this file to suit your needs. +version: '3.8' + +x-airflow-common: + &airflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/airflow:latest + platform: linux/amd64 + #build: + #context: ./cornflow-server/airflow_config + environment: + &airflow-common-env + AIRFLOW_USER: admin + AIRFLOW_PWD: admin + AIRFLOW_DB_HOST: airflow_db + AIRFLOW_DB_PORT: 5432 + AIRFLOW_DB_USER: airflow + AIRFLOW_DB_PASSWORD: airflow + AIRFLOW_DB: airflow + AIRFLOW__WEBSERVER__INSTANCE_NAME: CornflowEnv + AIRFLOW__WEBSERVER__NAVBAR_COLOR: '#0693e3' + volumes: + - ./cornflow-dags/DAG:/usr/local/airflow/dags + - ./cornflow-dags/requirements.txt:/requirements.txt + - ./cornflow-server/airflow_config/logs:/usr/local/airflow/logs + - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins + - ./cornflow-server/airflow_config/airflow_local_settings.py:/usr/local/airflow/config/airflow_local_settings.py + depends_on: + &airflow-common-depends-on + airflow_db: + condition: service_healthy + +x-cornflow-common: + &cornflow-common + # In order to add custom dependencies or upgrade provider packages you can use your extended image. + # Comment the image line and uncomment the "build" and "context" lines below, Then run `docker-compose build` to build the images. + image: baobabsoluciones/cornflow:release-v1.0.7 + platform: linux/amd64 + #build: + #context: ./cornflow-server + environment: + &cornflow-common-env + CORNFLOW_ADMIN_USER: cornflow_admin + CORNFLOW_ADMIN_PWD: Cornflow_admin1234 + CORNFLOW_SERVICE_USER: service_user + CORNFLOW_SERVICE_PWD: Service_user1234 + CORNFLOW_DB_HOST: cornflow_db + CORNFLOW_DB_PORT: 5432 + CORNFLOW_DB_USER: cornflow + CORNFLOW_DB_PASSWORD: cornflow + CORNFLOW_DB: cornflow + depends_on: + &cornflow-common-depends-on + cornflow_db: + condition: service_healthy + webserver: + condition: service_healthy services: cornflow: - build: - context: ./cornflow-server - dockerfile: Dockerfile + <<: *cornflow-common restart: always ports: - 5000:5000 + healthcheck: + test: ["CMD-SHELL", "[ -f /usr/src/app/gunicorn.pid ]"] + interval: 30s + timeout: 30s + retries: 5 environment: - - CORNFLOW_ADMIN_USER=cornflow_admin - - CORNFLOW_ADMIN_PWD=Cornflow_admin1234 - - CORNFLOW_SERVICE_USER=service_user - - CORNFLOW_SERVICE_PWD=Service_user1234 - - CORNFLOW_DB_HOST=cornflow_db - - CORNFLOW_DB_PORT=5432 - - CORNFLOW_DB_USER=cornflow - - CORNFLOW_DB_PASSWORD=cornflow - - CORNFLOW_DB=cornflow - - CF_ALARMS_ENDPOINT=0 + <<: *cornflow-common-env depends_on: - - cornflow_db - - webserver + <<: *cornflow-common-depends-on cornflow_db: - image: postgres + image: postgres:15.4 environment: - POSTGRES_USER=cornflow - POSTGRES_PASSWORD=cornflow - POSTGRES_DB=cornflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "cornflow"] + interval: 10s + retries: 5 + start_period: 5s + restart: always volumes: - postgres_cf_data:/var/lib/postgresql/data/ + + airflow_db: + image: postgres:15.4 + environment: + - POSTGRES_USER=airflow + - POSTGRES_PASSWORD=airflow + - POSTGRES_DB=airflow + healthcheck: + test: ["CMD", "pg_isready", "-U", "airflow"] + interval: 10s + retries: 5 + start_period: 5s + volumes: + - postgres_af_data:/var/lib/postgresql/data/ webserver: - build: - context: ./cornflow-server/airflow_config - dockerfile: Dockerfile - restart: always - volumes: - - ./cornflow-dags/DAG:/usr/local/airflow/dags - - ./cornflow-dags/requirements.txt:/requirements.txt - - ./cornflow-server/airflow_config/plugins:/usr/local/airflow/plugins - environment: - - AIRFLOW_USER=admin - - AIRFLOW_PWD=admin - - CORNFLOW_SERVICE_USER=service_user - - CORNFLOW_SERVICE_PWD=Service_user1234 - - AIRFLOW_DB_HOST=airflow_db - - AIRFLOW_DB_PORT=5432 - - AIRFLOW_DB_USER=airflow - - AIRFLOW_DB_PASSWORD=airflow - - AIRFLOW_DB=airflow + <<: *airflow-common + command: webserver ports: - 8080:8080 - depends_on: - - airflow_db - command: webserver healthcheck: test: ["CMD-SHELL", "[ -f /usr/local/airflow/airflow-webserver.pid ]"] interval: 30s timeout: 30s retries: 5 - - airflow_db: - image: postgres environment: - - POSTGRES_USER=airflow - - POSTGRES_PASSWORD=airflow - - POSTGRES_DB=airflow - volumes: - - postgres_af_data:/var/lib/postgresql/data/ + <<: *airflow-common-env + restart: always + depends_on: + <<: *airflow-common-depends-on volumes: postgres_cf_data: postgres_af_data: - From 17efc14f7c29c86fafc38ef7fc12e1cc74e5c14a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Fri, 13 Oct 2023 13:42:51 +0200 Subject: [PATCH 14/22] Now responses go back in the intended order instead of in alphabetical order (#485) --- cornflow-server/cornflow/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cornflow-server/cornflow/app.py b/cornflow-server/cornflow/app.py index 613d9e2a2..314a7627b 100644 --- a/cornflow-server/cornflow/app.py +++ b/cornflow-server/cornflow/app.py @@ -49,6 +49,7 @@ def create_app(env_name="development", dataconn=None): dictConfig(log_config(app_config[env_name].LOG_LEVEL)) app = Flask(__name__) + app.json.sort_keys = False app.logger.setLevel(app_config[env_name].LOG_LEVEL) app.config.from_object(app_config[env_name]) From 7c4dc95f770d2fff639cbd64fe7f971b3c8ac071 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillermo=20Gonz=C3=A1lez-Santander=20de=20la=20Cruz?= Date: Fri, 13 Oct 2023 16:01:07 +0200 Subject: [PATCH 15/22] Airflow variables (#486) * Changed the way we invoke the connection uri Changed the variable that setups the environment name * Updated unit test --- libs/client/cornflow_client/airflow/dag_utilities.py | 4 ++-- libs/client/cornflow_client/tests/unit/test_dag_utilities.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/client/cornflow_client/airflow/dag_utilities.py b/libs/client/cornflow_client/airflow/dag_utilities.py index 6e5a4ae5f..741b148e6 100644 --- a/libs/client/cornflow_client/airflow/dag_utilities.py +++ b/libs/client/cornflow_client/airflow/dag_utilities.py @@ -78,7 +78,7 @@ def connect_to_cornflow(secrets): """ # This secret comes from airflow configuration print("Getting connection information from ENV VAR=CF_URI") - uri = secrets.get_conn_uri("CF_URI") + uri = secrets.get_conn_value("CF_URI") conn = urlparse(uri) scheme = conn.scheme if scheme == "cornflow": @@ -326,7 +326,7 @@ def callback_email(context): notification_email = EnvironmentVariablesBackend().get_variable( "NOTIFICATION_EMAIL" ) - environment_name = EnvironmentVariablesBackend().get_variable("ENVIRONMENT_NAME") + environment_name = os.getenv("AIRFLOW__WEBSERVER__INSTANCE_NAME", "CornflowEnv") title = f"Airflow. {environment_name} ({environment}). DAG/task error: {context['dag'].dag_id}/{context['ti'].task_id} Failed" body = f""" diff --git a/libs/client/cornflow_client/tests/unit/test_dag_utilities.py b/libs/client/cornflow_client/tests/unit/test_dag_utilities.py index fdaa33abb..6469dd850 100644 --- a/libs/client/cornflow_client/tests/unit/test_dag_utilities.py +++ b/libs/client/cornflow_client/tests/unit/test_dag_utilities.py @@ -31,8 +31,8 @@ def test_env_connection_vars(self, CornFlow): ] client_instance = CornFlow.return_value client_instance.login.return_value = "" - for (conn_str, user_info, url) in conn_uris: - secrets.get_conn_uri.return_value = conn_str + for conn_str, user_info, url in conn_uris: + secrets.get_conn_value.return_value = conn_str du.connect_to_cornflow(secrets) client_instance.login.assert_called_with( username=user_info[0], pwd=user_info[1] From 0c3f143d34b1f4b51c90f613caca1f1bd6787fb0 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 13 Oct 2023 18:37:10 +0200 Subject: [PATCH 16/22] Bumped versions on release branch --- cornflow-server/Dockerfile | 4 ++-- cornflow-server/changelog.rst | 3 +++ cornflow-server/requirements.txt | 2 +- cornflow-server/setup.py | 2 +- libs/client/changelog.rst | 7 +++++++ libs/client/requirements.txt | 12 ++++++------ libs/client/setup.py | 2 +- 7 files changed, 21 insertions(+), 11 deletions(-) diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index c655aff9d..701ae4509 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -1,4 +1,4 @@ -# VERSION 1.0.8a1 +# VERSION 1.0.8a3 # AUTHOR: sistemas@baobabsoluciones.es FROM python:3.10-slim-buster @@ -9,7 +9,7 @@ ENV DEBIAN_FRONTEND noninteractive ENV TERM linux # CORNFLOW vars -ARG CORNFLOW_VERSION=1.0.8a2 +ARG CORNFLOW_VERSION=1.0.8a3 # install linux pkg RUN apt update -y && apt-get install -y --no-install-recommends \ diff --git a/cornflow-server/changelog.rst b/cornflow-server/changelog.rst index 15f7e6857..ae40bd033 100644 --- a/cornflow-server/changelog.rst +++ b/cornflow-server/changelog.rst @@ -1,6 +1,9 @@ version 1.0.8 -------------- +- released: +- description: +- changelog: version 1.0.7 diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index 0e646c117..f6276b5a1 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -1,7 +1,7 @@ alembic==1.9.2 apispec<=6.2.0 click<=8.1.3 -cornflow-client==1.0.16a1 +cornflow-client==1.0.16a2 cryptography<=39.0.2 disposable-email-domains>=0.0.86 Flask==2.3.2 diff --git a/cornflow-server/setup.py b/cornflow-server/setup.py index a6ca656a0..a3cea6232 100644 --- a/cornflow-server/setup.py +++ b/cornflow-server/setup.py @@ -9,7 +9,7 @@ setuptools.setup( name="cornflow", - version="1.0.8a2", + version="1.0.8a3", author="baobab soluciones", author_email="cornflow@baobabsoluciones.es", description="Cornflow is an open source multi-solver optimization server with a REST API built using flask.", diff --git a/libs/client/changelog.rst b/libs/client/changelog.rst index e7828d0bc..43302c3a4 100644 --- a/libs/client/changelog.rst +++ b/libs/client/changelog.rst @@ -1,10 +1,17 @@ version 1.0.16 --------------- +- released: +- description: +- changelog: version 1.0.15 --------------- +- released: 2023-10-04 +- description: dropped Python 3.7 support +- changelog: + - dropped python 3.7 support as will the rest of components. version 1.0.14 diff --git a/libs/client/requirements.txt b/libs/client/requirements.txt index dbbe3ff88..dc103daed 100644 --- a/libs/client/requirements.txt +++ b/libs/client/requirements.txt @@ -1,8 +1,8 @@ -requests==2.31.0 -genson -jsonschema +requests<=2.31.0 +genson<=1.2.2 +jsonschema<=4.19.1 marshmallow<=3.19.0 -pytups>=0.86.2 -ortools +pytups<=0.86.2 +ortools<=9.7.2996 pandas>=1.5.2 -PuLP>=2.3 \ No newline at end of file +PuLP<=2.7.0 \ No newline at end of file diff --git a/libs/client/setup.py b/libs/client/setup.py index e5ffcc364..49eed1f3e 100644 --- a/libs/client/setup.py +++ b/libs/client/setup.py @@ -12,7 +12,7 @@ setuptools.setup( name="cornflow-client", - version="1.0.16a1", + version="1.0.16a2", author="baobab soluciones", author_email="sistemas@baobabsoluciones.es", description="Client to connect to a cornflow server", From 82a7ecc61c6151c40ea050424e7823ef40c46fb2 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 13 Oct 2023 18:38:17 +0200 Subject: [PATCH 17/22] Requirements for DAGS --- cornflow-dags/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index d5fa1917c..206e98896 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,4 +1,4 @@ -cornflow-client==1.0.16a1 +cornflow-client==1.0.16a2 orloge<=0.17.2 PuLP<=2.7 pandas<=2.1.1 From 99dd0e67fc4e5b494c7c15bef76b466fb179e55b Mon Sep 17 00:00:00 2001 From: dag Date: Tue, 17 Oct 2023 15:04:45 +0200 Subject: [PATCH 18/22] Feature/af from docker base (#487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * create Dockerfile.base for pysolver docker img * default solvers: cbc, gurobi, highs --------- Co-authored-by: Guillermo González-Santander de la Cruz --- cornflow-server/airflow_config/Dockerfile | 56 ++-------------- .../airflow_config/Dockerfile.base | 66 +++++++++++++++++++ .../scripts/solver_installation.py | 6 +- .../scripts/solvers/get_choco.py | 2 +- .../scripts/solvers/get_gurobi.py | 9 +-- .../scripts/solvers/get_highs.py | 2 +- .../scripts/solvers/get_mipcl.py | 2 +- 7 files changed, 83 insertions(+), 60 deletions(-) create mode 100644 cornflow-server/airflow_config/Dockerfile.base diff --git a/cornflow-server/airflow_config/Dockerfile b/cornflow-server/airflow_config/Dockerfile index 44239dcba..ddfe9a4fa 100644 --- a/cornflow-server/airflow_config/Dockerfile +++ b/cornflow-server/airflow_config/Dockerfile @@ -1,8 +1,8 @@ # VERSION 2.7.1 # AUTHOR: cornflow@baobabsoluciones.es -# DESCRIPTION: Airflow 2.7.1 image personalized for use with Cornflow (from puckel/docker-airflow https://github.com/puckel/docker-airflow by "Puckel_") +# DESCRIPTION: Airflow 2.7.1 image personalized for use with Cornflow (from baobabsoluciones/pysolver image) -FROM python:3.10-slim-buster +FROM baobabsoluciones/pysolver:1.0 LABEL maintainer="cornflow@baobabsoluciones" # Never prompt the user for choices on installation/configuration of packages @@ -16,45 +16,8 @@ ARG CONSTRAINT_URL="https://raw.githubusercontent.com/apache/airflow/constraints ARG AIRFLOW__CORE__LOAD_EXAMPLES=False ENV AIRFLOW_HOME=${AIRFLOW_USER_HOME} -# install Airflow requirements -RUN apt update -y && apt-get install -y --no-install-recommends \ - apt-utils \ - default-jre \ - default-jdk \ - g++ \ - gcc \ - git \ - freetds-bin \ - krb5-user \ - ldap-utils \ - libffi6 \ - libffi-dev \ - libldap2-dev \ - libpq-dev \ - libprotobuf-dev \ - libsasl2-2 \ - libsasl2-dev \ - libsasl2-modules \ - libssl1.1 \ - libssl-dev \ - locales \ - lsb-release \ - make \ - pkg-config \ - protobuf-compiler \ - python3-dev \ - sasl2-bin \ - slapd \ - sqlite3 \ - ssh \ - unixodbc \ - wget - # install Airflow and extras: celery,postgres and redis RUN pip install "apache-airflow[celery,google,postgres,redis,sendgrid]==${AIRFLOW_VERSION}" --constraint "${CONSTRAINT_URL}" -RUN pip install python-ldap -RUN pip install GitPython -RUN pip install cmake # copy init script and config to container COPY scripts ${AIRFLOW_HOME}/scripts @@ -64,20 +27,13 @@ COPY webserver_ldap.py ${AIRFLOW_HOME}/webserver_ldap.py # create folder for custom ssh keys RUN mkdir ${AIRFLOW_HOME}/.ssh -# user airflow on application -RUN useradd -ms /bin/bash -d ${AIRFLOW_HOME} airflow -RUN chown -R airflow: ${AIRFLOW_HOME} - -# execute installation solvers script -RUN python ${AIRFLOW_HOME}/scripts/solver_installation.py -ENV GUROBI_HOME=${AIRFLOW_HOME}/gurobi/linux64 -ENV PATH=${PATH}:${GUROBI_HOME}/bin -ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GUROBI_HOME}/lib -ENV GRB_LICENSE_FILE=${AIRFLOW_HOME}/gurobi.lic +# rights for user cornflow on application +RUN chown -R cornflow: ${AIRFLOW_HOME} EXPOSE 8080 5555 8793 -USER airflow +# change user to cornflow +USER cornflow WORKDIR ${AIRFLOW_HOME} ENTRYPOINT ["python", "scripts/init_airflow_service.py"] diff --git a/cornflow-server/airflow_config/Dockerfile.base b/cornflow-server/airflow_config/Dockerfile.base new file mode 100644 index 000000000..6281549a1 --- /dev/null +++ b/cornflow-server/airflow_config/Dockerfile.base @@ -0,0 +1,66 @@ +# VERSION 1.0 +# AUTHOR: cornflow@baobabsoluciones.es + +FROM python:3.10-slim-buster +LABEL maintainer="cornflow@baobabsoluciones" + +# Never prompt the user for choices on installation/configuration of packages +ENV DEBIAN_FRONTEND noninteractive +ENV TERM linux + +# solver vars +ENV SOLVER_DIR=/usr/local/solvers + +# install linux requirements +RUN apt update -y && apt-get install -y --no-install-recommends \ + apt-utils \ + default-jre \ + default-jdk \ + g++ \ + gcc \ + git \ + freetds-bin \ + krb5-user \ + ldap-utils \ + libffi6 \ + libffi-dev \ + libldap2-dev \ + libpq-dev \ + libprotobuf-dev \ + libsasl2-2 \ + libsasl2-dev \ + libsasl2-modules \ + libssl1.1 \ + libssl-dev \ + locales \ + lsb-release \ + make \ + pkg-config \ + protobuf-compiler \ + python3-dev \ + sasl2-bin \ + slapd \ + sqlite3 \ + ssh \ + unixodbc \ + wget + +RUN pip install python-ldap +RUN pip install GitPython +RUN pip install cmake + +# copy init script and config to container +COPY scripts ${SOLVER_DIR}/scripts + +# add user cornflow on application +RUN useradd -ms /bin/bash -d ${SOLVER_DIR} cornflow +RUN chown -R cornflow: ${SOLVER_DIR} + +# execute installation solvers script +RUN python ${SOLVER_DIR}/scripts/solver_installation.py +ENV GUROBI_HOME=${SOLVER_DIR}/gurobi/linux64 +ENV PATH=${PATH}:${GUROBI_HOME}/bin +ENV LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${GUROBI_HOME}/lib +ENV GRB_LICENSE_FILE=${GUROBI_HOME}/gurobi.lic + +WORKDIR ${SOLVER_DIR} \ No newline at end of file diff --git a/cornflow-server/airflow_config/scripts/solver_installation.py b/cornflow-server/airflow_config/scripts/solver_installation.py index 75347662f..a63cba0ba 100644 --- a/cornflow-server/airflow_config/scripts/solver_installation.py +++ b/cornflow-server/airflow_config/scripts/solver_installation.py @@ -8,11 +8,11 @@ # * MIPCL: https://github.com/onebitbrain/MIPCL/blob/master/bin/mps_mipcl # * glpk: https://www.gnu.org/software/glpk/ # * Gurobi optimizer: https://www.gurobi.com/ -available_solver = ["HiGHS", "CBC", "CHOCO", "glpk", "gurobi"] +available_solver = "HiGHS,CBC,CHOCO,glpk,gurobi" +default_solvers = "HiGHS,CBC,gurobi" # list of solvers that will be installed -solver_list = os.getenv("SOLVER_LIST", "CBC,glpk,HiGHS,CHOCO,MIPCL,gurobi").split(",") - +solver_list = os.getenv("SOLVER_LIST", default_solvers).split(",") def install(s): if s in "CBC": diff --git a/cornflow-server/airflow_config/scripts/solvers/get_choco.py b/cornflow-server/airflow_config/scripts/solvers/get_choco.py index f7aa0118c..b25790ced 100644 --- a/cornflow-server/airflow_config/scripts/solvers/get_choco.py +++ b/cornflow-server/airflow_config/scripts/solvers/get_choco.py @@ -30,7 +30,7 @@ def install(): ) output_choco = choco_install.stdout print(output_choco) - uid = pwd.getpwnam("airflow").pw_uid + uid = pwd.getpwnam("cornflow").pw_uid gid = grp.getgrnam("root").gr_gid choco_path = "/usr/local/bin/choco.jar" os.chown(choco_path, uid, gid) diff --git a/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py b/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py index 522cb4f43..8a77af20f 100644 --- a/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py +++ b/cornflow-server/airflow_config/scripts/solvers/get_gurobi.py @@ -19,15 +19,16 @@ def install(): try: - install_dir = "/usr/local/airflow/gurobi" - os.chdir("/usr/local/airflow") + solver_dir = os.getenv("SOLVER_DIR") + install_dir = solver_dir+"/gurobi" + os.chdir(solver_dir) subprocess.check_output( ["wget", "https://packages.gurobi.com/10.0/gurobi10.0.1_linux64.tar.gz"] ) subprocess.check_output(["tar", "-xvf", "gurobi10.0.1_linux64.tar.gz"]) os.rename("gurobi1001", "gurobi") - uid = pwd.getpwnam("airflow").pw_uid - gid = grp.getgrnam("airflow").gr_gid + uid = pwd.getpwnam("cornflow").pw_uid + gid = grp.getgrnam("cornflow").gr_gid os.chown(install_dir, uid, gid) os.chdir(f"{install_dir}/linux64") gurobi_install = subprocess.run( diff --git a/cornflow-server/airflow_config/scripts/solvers/get_highs.py b/cornflow-server/airflow_config/scripts/solvers/get_highs.py index 9fc7240ef..6a0cf1d4b 100644 --- a/cornflow-server/airflow_config/scripts/solvers/get_highs.py +++ b/cornflow-server/airflow_config/scripts/solvers/get_highs.py @@ -29,7 +29,7 @@ def install(): subprocess.check_output("make") subprocess.check_output(["cp", "bin/highs", "/usr/local/bin/highs"]) subprocess.check_output(["chmod", "+x", "/usr/local/bin/highs"]) - uid = pwd.getpwnam("airflow").pw_uid + uid = pwd.getpwnam("cornflow").pw_uid gid = grp.getgrnam("root").gr_gid highs_path = "/usr/local/bin/highs" os.chown(highs_path, uid, gid) diff --git a/cornflow-server/airflow_config/scripts/solvers/get_mipcl.py b/cornflow-server/airflow_config/scripts/solvers/get_mipcl.py index bd6224411..8dc7aa9d2 100644 --- a/cornflow-server/airflow_config/scripts/solvers/get_mipcl.py +++ b/cornflow-server/airflow_config/scripts/solvers/get_mipcl.py @@ -25,7 +25,7 @@ def install(): os.chdir(f"{MIPCL.working_dir}/bin") subprocess.check_output(["cp", "mps_mipcl", "/usr/local/bin/mps_mipcl"]) subprocess.check_output(["chmod", "+x", "/usr/local/bin/mps_mipcl"]) - uid = pwd.getpwnam("airflow").pw_uid + uid = pwd.getpwnam("cornflow").pw_uid gid = grp.getgrnam("root").gr_gid mips_path = "/usr/local/bin/mps_mipcl" os.chown(mips_path, uid, gid) From aa92fcf77fd6a2554c185f104d41377f8ae247e7 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 20 Oct 2023 09:47:00 +0200 Subject: [PATCH 19/22] Bump final version --- cornflow-dags/requirements.txt | 2 +- cornflow-server/Dockerfile | 4 ++-- cornflow-server/airflow_config/Dockerfile | 1 + cornflow-server/changelog.rst | 11 +++++++++-- cornflow-server/requirements.txt | 2 +- libs/client/changelog.rst | 4 ++-- libs/client/setup.py | 2 +- 7 files changed, 17 insertions(+), 9 deletions(-) diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 206e98896..38b1e3fcd 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,4 +1,4 @@ -cornflow-client==1.0.16a2 +cornflow-client>=1.0.16 orloge<=0.17.2 PuLP<=2.7 pandas<=2.1.1 diff --git a/cornflow-server/Dockerfile b/cornflow-server/Dockerfile index 26968cef1..79e31140a 100644 --- a/cornflow-server/Dockerfile +++ b/cornflow-server/Dockerfile @@ -1,4 +1,4 @@ -# VERSION 1.0.8a3 +# VERSION 1.0.8 # AUTHOR: sistemas@baobabsoluciones.es FROM python:3.10-slim-buster @@ -9,7 +9,7 @@ ENV DEBIAN_FRONTEND noninteractive ENV TERM linux # CORNFLOW vars -ARG CORNFLOW_VERSION=1.0.8a3 +ARG CORNFLOW_VERSION=1.0.8 # install linux pkg RUN apt update -y && apt-get install -y --no-install-recommends \ diff --git a/cornflow-server/airflow_config/Dockerfile b/cornflow-server/airflow_config/Dockerfile index ddfe9a4fa..f0ae2ca64 100644 --- a/cornflow-server/airflow_config/Dockerfile +++ b/cornflow-server/airflow_config/Dockerfile @@ -1,6 +1,7 @@ # VERSION 2.7.1 # AUTHOR: cornflow@baobabsoluciones.es # DESCRIPTION: Airflow 2.7.1 image personalized for use with Cornflow (from baobabsoluciones/pysolver image) +# baobab code version is 1.0.8 FROM baobabsoluciones/pysolver:1.0 LABEL maintainer="cornflow@baobabsoluciones" diff --git a/cornflow-server/changelog.rst b/cornflow-server/changelog.rst index ae40bd033..c6fc41feb 100644 --- a/cornflow-server/changelog.rst +++ b/cornflow-server/changelog.rst @@ -1,9 +1,16 @@ version 1.0.8 -------------- -- released: -- description: +- released: 2023-10-20 +- description: new version of cornflow with new features and bug fixes. - changelog: + - This version of cornflow is only compatible with Python versions 3.8 or higher, with the desired version for deployment being Python version 3.10 (preferred version for baobab development as well). + - This version of cornflow updates the version of airflow to 2.7.1. + - Almost all library versions have been fixed to avoid dependency problems in future deployments. + - In the ApplicationCore you can define a new class-level argument (like schemas) which is notify. This argument, when True, automatically adds a callback that will send us an email with the log attached in case the model fails when running in Airflow. + - There is a new default DAG (run_deployed_models) that allows us to automatically launch all the models that we have deployed and for which we have defined a test instance in the ApplicationCore definition, so that once deployed we can do a quick test of the correct functioning of the model. + - If we create an execution and in the configuration we have not included all the information, the default values defined in the configuration json schema are taken. + - A command that used to convert models from an external app to jsonschemas is now disabled. version 1.0.7 diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index f6276b5a1..ca11b1310 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -1,7 +1,7 @@ alembic==1.9.2 apispec<=6.2.0 click<=8.1.3 -cornflow-client==1.0.16a2 +cornflow-client>=1.0.16 cryptography<=39.0.2 disposable-email-domains>=0.0.86 Flask==2.3.2 diff --git a/libs/client/changelog.rst b/libs/client/changelog.rst index 43302c3a4..f741ec520 100644 --- a/libs/client/changelog.rst +++ b/libs/client/changelog.rst @@ -1,8 +1,8 @@ version 1.0.16 --------------- -- released: -- description: +- released: 2023-10-20 +- description: Small fixes to the cornflow-client - changelog: version 1.0.15 diff --git a/libs/client/setup.py b/libs/client/setup.py index 49eed1f3e..6f2a9fcc5 100644 --- a/libs/client/setup.py +++ b/libs/client/setup.py @@ -12,7 +12,7 @@ setuptools.setup( name="cornflow-client", - version="1.0.16a2", + version="1.0.16", author="baobab soluciones", author_email="sistemas@baobabsoluciones.es", description="Client to connect to a cornflow server", From b94cd898f887ce92d42ceb99480b2deeb417d3f7 Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 20 Oct 2023 09:50:49 +0200 Subject: [PATCH 20/22] Missing code on cornflow-server setup --- cornflow-server/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cornflow-server/setup.py b/cornflow-server/setup.py index a3cea6232..9cb3f0b27 100644 --- a/cornflow-server/setup.py +++ b/cornflow-server/setup.py @@ -9,7 +9,7 @@ setuptools.setup( name="cornflow", - version="1.0.8a3", + version="1.0.8", author="baobab soluciones", author_email="cornflow@baobabsoluciones.es", description="Cornflow is an open source multi-solver optimization server with a REST API built using flask.", From 4105730c16eb6889de910c5a9ec05f5e631f3f3f Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 20 Oct 2023 09:52:51 +0200 Subject: [PATCH 21/22] Update requirements --- cornflow-dags/requirements.txt | 2 +- cornflow-server/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 38b1e3fcd..21476d0a2 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,4 +1,4 @@ -cornflow-client>=1.0.16 +cornflow-client>=1.0.16a1 orloge<=0.17.2 PuLP<=2.7 pandas<=2.1.1 diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index ca11b1310..8e914ce2a 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -1,7 +1,7 @@ alembic==1.9.2 apispec<=6.2.0 click<=8.1.3 -cornflow-client>=1.0.16 +cornflow-client>=1.0.16a1 cryptography<=39.0.2 disposable-email-domains>=0.0.86 Flask==2.3.2 From 2dd57510202f0987e3366ffa0121479584ce3f9a Mon Sep 17 00:00:00 2001 From: Guillermo Gonzalez-Santander Date: Fri, 20 Oct 2023 09:53:20 +0200 Subject: [PATCH 22/22] Final update of requirements --- cornflow-dags/requirements.txt | 2 +- cornflow-server/requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cornflow-dags/requirements.txt b/cornflow-dags/requirements.txt index 21476d0a2..a67663a50 100644 --- a/cornflow-dags/requirements.txt +++ b/cornflow-dags/requirements.txt @@ -1,4 +1,4 @@ -cornflow-client>=1.0.16a1 +cornflow-client<=1.0.16 orloge<=0.17.2 PuLP<=2.7 pandas<=2.1.1 diff --git a/cornflow-server/requirements.txt b/cornflow-server/requirements.txt index 8e914ce2a..185d44355 100644 --- a/cornflow-server/requirements.txt +++ b/cornflow-server/requirements.txt @@ -1,7 +1,7 @@ alembic==1.9.2 apispec<=6.2.0 click<=8.1.3 -cornflow-client>=1.0.16a1 +cornflow-client<=1.0.16 cryptography<=39.0.2 disposable-email-domains>=0.0.86 Flask==2.3.2