{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Getting Started with TimeDataModel\n",
    "\n",
    "TimeDataModel is a lightweight Python data model for time series data. It gives you structured, metadata-rich time series objects with seamless bridges to pandas, numpy, and polars. This notebook walks you through the basics: creating a `TimeSeries`, inspecting it, and converting it."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Installation\n",
    "\n",
    "```bash\n",
    "pip install timedatamodel\n",
    "\n",
    "# With optional extras\n",
    "pip install timedatamodel[polars]   # polars support\n",
    "pip install timedatamodel[geo]      # GeoArea support via shapely\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating your first TimeSeries\n",
    "\n",
    "A `TimeSeries` needs a frequency, timestamps, and values. You can optionally attach metadata like a name, unit, and data type."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.091054Z",
     "iopub.status.busy": "2026-03-01T13:36:36.090947Z",
     "iopub.status.idle": "2026-03-01T13:36:36.150781Z",
     "shell.execute_reply": "2026-03-01T13:36:36.150348Z"
    }
   },
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'timedatamodel'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mModuleNotFoundError\u001b[39m                       Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[1]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m      1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mdatetime\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m datetime, timedelta, timezone\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m \u001b[38;5;28;01mimport\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mtimedatamodel\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mas\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mtdm\u001b[39;00m\n\u001b[32m      5\u001b[39m base = datetime(\u001b[32m2024\u001b[39m, \u001b[32m1\u001b[39m, \u001b[32m15\u001b[39m, tzinfo=timezone.utc)\n\u001b[32m      6\u001b[39m timestamps = [base + timedelta(hours=i) \u001b[38;5;28;01mfor\u001b[39;00m i \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(\u001b[32m24\u001b[39m)]\n",
      "\u001b[31mModuleNotFoundError\u001b[39m: No module named 'timedatamodel'"
     ]
    }
   ],
   "source": [
    "from datetime import datetime, timedelta, timezone\n",
    "\n",
    "import timedatamodel as tdm\n",
    "\n",
    "base = datetime(2024, 1, 15, tzinfo=timezone.utc)\n",
    "timestamps = [base + timedelta(hours=i) for i in range(24)]\n",
    "values = [\n",
    "    120.0, 115.0, 108.0, 105.0, 102.0, 100.0,\n",
    "    110.0, 135.0, 160.0, 175.0, 180.0, 178.0,\n",
    "    172.0, 170.0, 168.0, 165.0, 175.0, 190.0,\n",
    "    200.0, 195.0, 180.0, 165.0, 145.0, 130.0,\n",
    "]\n",
    "\n",
    "ts = tdm.TimeSeries(\n",
    "    tdm.Frequency.PT1H,\n",
    "    timezone=\"UTC\",\n",
    "    timestamps=timestamps,\n",
    "    values=values,\n",
    "    name=\"power\",\n",
    "    unit=\"MW\",\n",
    "    description=\"Hourly power output from wind farm Alpha\",\n",
    "    data_type=tdm.DataType.MEASUREMENT,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Rich notebook display\n",
    "\n",
    "Simply evaluate a `TimeSeries` in a cell to see its HTML representation — metadata and a data preview with head/tail rows."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.151805Z",
     "iopub.status.busy": "2026-03-01T13:36:36.151743Z",
     "iopub.status.idle": "2026-03-01T13:36:36.157916Z",
     "shell.execute_reply": "2026-03-01T13:36:36.157539Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'ts' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mts\u001b[49m\n",
      "\u001b[31mNameError\u001b[39m: name 'ts' is not defined"
     ]
    }
   ],
   "source": [
    "ts"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## DataPoints and iteration\n",
    "\n",
    "Each element in a `TimeSeries` is a `DataPoint` — a named tuple of `(timestamp, value)`. You can index, slice, and iterate."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.158848Z",
     "iopub.status.busy": "2026-03-01T13:36:36.158793Z",
     "iopub.status.idle": "2026-03-01T13:36:36.165362Z",
     "shell.execute_reply": "2026-03-01T13:36:36.164975Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'ts' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[3]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m dp = \u001b[43mts\u001b[49m[\u001b[32m0\u001b[39m]\n\u001b[32m      2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mFirst point: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdp\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m      3\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m  timestamp = \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdp.timestamp\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
      "\u001b[31mNameError\u001b[39m: name 'ts' is not defined"
     ]
    }
   ],
   "source": [
    "dp = ts[0]\n",
    "print(f\"First point: {dp}\")\n",
    "print(f\"  timestamp = {dp.timestamp}\")\n",
    "print(f\"  value     = {dp.value}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.166196Z",
     "iopub.status.busy": "2026-03-01T13:36:36.166135Z",
     "iopub.status.idle": "2026-03-01T13:36:36.172081Z",
     "shell.execute_reply": "2026-03-01T13:36:36.171704Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'ts' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[4]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[43mts\u001b[49m[:\u001b[32m3\u001b[39m]\n",
      "\u001b[31mNameError\u001b[39m: name 'ts' is not defined"
     ]
    }
   ],
   "source": [
    "ts[:3]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.172879Z",
     "iopub.status.busy": "2026-03-01T13:36:36.172825Z",
     "iopub.status.idle": "2026-03-01T13:36:36.179378Z",
     "shell.execute_reply": "2026-03-01T13:36:36.179068Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'ts' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28;01mfor\u001b[39;00m dp \u001b[38;5;129;01min\u001b[39;00m \u001b[43mts\u001b[49m.head(\u001b[32m4\u001b[39m):\n\u001b[32m      2\u001b[39m     \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdp.timestamp\u001b[38;5;132;01m:\u001b[39;00m\u001b[33m%H:%M\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m  \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdp.value\u001b[38;5;132;01m:\u001b[39;00m\u001b[33m>6.1f\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m MW\u001b[39m\u001b[33m\"\u001b[39m)\n",
      "\u001b[31mNameError\u001b[39m: name 'ts' is not defined"
     ]
    }
   ],
   "source": [
    "for dp in ts.head(4):\n",
    "    print(f\"{dp.timestamp:%H:%M}  {dp.value:>6.1f} MW\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Inspecting properties\n",
    "\n",
    "A `TimeSeries` exposes handy properties for quick inspection."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.180477Z",
     "iopub.status.busy": "2026-03-01T13:36:36.180394Z",
     "iopub.status.idle": "2026-03-01T13:36:36.187391Z",
     "shell.execute_reply": "2026-03-01T13:36:36.187009Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'ts' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mLength:      \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mlen\u001b[39m(\u001b[43mts\u001b[49m)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m points\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m      2\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mBegin:       \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mts.begin\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n\u001b[32m      3\u001b[39m \u001b[38;5;28mprint\u001b[39m(\u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mEnd:         \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mts.end\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m)\n",
      "\u001b[31mNameError\u001b[39m: name 'ts' is not defined"
     ]
    }
   ],
   "source": [
    "print(f\"Length:      {len(ts)} points\")\n",
    "print(f\"Begin:       {ts.begin}\")\n",
    "print(f\"End:         {ts.end}\")\n",
    "print(f\"Duration:    {ts.duration}\")\n",
    "print(f\"Has missing: {ts.has_missing}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Creating from DataPoints\n",
    "\n",
    "You can also construct a `TimeSeries` from a list of `DataPoint` objects."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-03-01T13:36:36.188302Z",
     "iopub.status.busy": "2026-03-01T13:36:36.188250Z",
     "iopub.status.idle": "2026-03-01T13:36:36.195546Z",
     "shell.execute_reply": "2026-03-01T13:36:36.195182Z"
    }
   },
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'tdm' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mNameError\u001b[39m                                 Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[7]\u001b[39m\u001b[32m, line 2\u001b[39m\n\u001b[32m      1\u001b[39m data = [\n\u001b[32m----> \u001b[39m\u001b[32m2\u001b[39m     \u001b[43mtdm\u001b[49m.DataPoint(datetime(\u001b[32m2024\u001b[39m, \u001b[32m1\u001b[39m, \u001b[32m15\u001b[39m, h, tzinfo=timezone.utc), v)\n\u001b[32m      3\u001b[39m     \u001b[38;5;28;01mfor\u001b[39;00m h, v \u001b[38;5;129;01min\u001b[39;00m [(\u001b[32m0\u001b[39m, \u001b[32m5.2\u001b[39m), (\u001b[32m1\u001b[39m, \u001b[32m5.8\u001b[39m), (\u001b[32m2\u001b[39m, \u001b[32m6.1\u001b[39m), (\u001b[32m3\u001b[39m, \u001b[32m5.5\u001b[39m)]\n\u001b[32m      4\u001b[39m ]\n\u001b[32m      6\u001b[39m ts_temp = tdm.TimeSeries(\n\u001b[32m      7\u001b[39m     tdm.Frequency.PT1H,\n\u001b[32m      8\u001b[39m     data=data,\n\u001b[32m      9\u001b[39m     name=\u001b[33m\"\u001b[39m\u001b[33mtemperature\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m     10\u001b[39m     unit=\u001b[33m\"\u001b[39m\u001b[33m°C\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m     11\u001b[39m )\n\u001b[32m     12\u001b[39m ts_temp\n",
      "\u001b[31mNameError\u001b[39m: name 'tdm' is not defined"
     ]
    }
   ],
   "source": [
    "data = [\n",
    "    tdm.DataPoint(datetime(2024, 1, 15, h, tzinfo=timezone.utc), v)\n",
    "    for h, v in [(0, 5.2), (1, 5.8), (2, 6.1), (3, 5.5)]\n",
    "]\n",
    "\n",
    "ts_temp = tdm.TimeSeries(\n",
    "    tdm.Frequency.PT1H,\n",
    "    data=data,\n",
    "    name=\"temperature\",\n",
    "    unit=\"°C\",\n",
    ")\n",
    "ts_temp"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Summary\n",
    "\n",
    "In this notebook you learned how to:\n",
    "\n",
    "- Create a `TimeSeries` with metadata (name, unit, data type)\n",
    "- View its rich display in a notebook\n",
    "- Access individual `DataPoint` elements via indexing, slicing, and iteration\n",
    "- Inspect basic properties: `begin`, `end`, `duration`, `has_missing`\n",
    "\n",
    "Next up: **nb_02** shows how to use numpy and pandas to transform time series data."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.14.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
