# Weekly data

Read twelve weeks of disease counts per district from DHIS2 analytics, with the periods in DHIS2's own calendar.

This page follows [Setup](https://zato.io/docs/dev/healthcare/dhis2/outbreak-alerts/setup.html) in the [Outbreak alerts](https://zato.io/docs/dev/healthcare/dhis2/outbreak-alerts/index.html) series. Facilities report their counts, and the analytics API returns them added up to any level of the organisation unit hierarchy. One request gives the counts of every disease in every district for the week just ended and the eleven weeks before it, which is what the thresholds on the next page are computed from.

## The request {#the-request}

The analytics API takes one `dimension` parameter per dimension of the result - `dx` for the data elements, `pe` for the periods and `ou` for the organisation units:

```python
# -*- coding: utf-8 -*-

# Zato
from zato.server.service import Service

class CheckWeek(Service):
    name = 'dhis2.alerts.check-week'

    def read_analytics(self) -> 'dict':

        alerts = self.config.alerts

        # One data element per disease ..
        data_elements = []
        for disease in alerts.diseases.values():
            data_elements.append(disease.data_element)

        # .. twelve weeks ending with the one just ended, and every district.
        dx = ';'.join(data_elements)
        level = alerts.analytics.district_level
        dimensions = [f'dx:{dx}', 'pe:LAST_12_WEEKS', f'ou:LEVEL-{level}']
        params = {'dimension': dimensions}

        conn = self.rest['DHIS2 Analytics']
        response = conn.get(params=params)

        out = response.data
        return out
```

A list in `params` becomes a query parameter repeated once per item. `LAST_12_WEEKS` is a relative period, which DHIS2 resolves on its own side, and `LEVEL-2` selects every organisation unit on the second level of the hierarchy.

## The counts {#the-counts}

Each row of the response is a data element, a week, a district and a count, in that order. A week in which a district reported no cases of a disease has no row, so each series starts at zero for every week and the rows fill it in:

```python
    def read_series(self) -> 'tuple[list, dict]':

        analytics = self.read_analytics()

        # The weeks in calendar order, the last one being the week just ended ..
        metadata = analytics['metaData']
        dimensions = metadata['dimensions']
        weeks = dimensions['pe']
        week_count = len(weeks)

        series = {}

        # .. and each row is a count of one disease in one district and one week.
        for data_element, week, district, value in analytics['rows']:

            # Every week of a district and disease starts at zero ..
            key = (data_element, district)
            if key not in series:
                series[key] = [0.0] * week_count

            # .. and the count goes into its week.
            counts = series[key]
            index = weeks.index(week)
            counts[index] = float(value)

        out = weeks, series
        return out
```

`metaData.dimensions.pe` lists the weeks in calendar order. The rows come in no particular order, which is why each count is placed by the position of its week in that list.

## Periods {#periods}

DHIS2 identifies each period by a string, and every value a service reads or writes carries one:

| Period | Identifier | Example |
| --- | --- | --- |
| ISO week | `yyyyWn` | `2026W40` |
| Week starting on Wednesday | `yyyyWedWn` | `2026WedW40` |
| Month | `yyyyMM` | `202609` |
| Day | `yyyyMMdd` | `20261005` |

The week number has no leading zero, so `2026W9` comes before `2026W10` although it sorts after it as a string. A data set whose weeks start on a day other than Monday uses the matching weekly period type, such as `WedW` for Wednesday, and takes values only for periods of that type.

A DHIS2 instance can also run on a calendar other than the Gregorian one, such as the Ethiopian or the Nepali calendar. Its period identifiers are then in that calendar, and a week or month computed in Python from a Gregorian date names a different period.

Relative periods such as `LAST_12_WEEKS`, `LAST_WEEK` or `LAST_MONTH` are resolved by DHIS2 in its own calendar. The identifiers it returns in `metaData` are the ones to use in anything written back, which is why the services in this series do not compute any period themselves.

## The schedule {#the-schedule}

The service runs from a [scheduler](https://zato.io/docs/dev/examples/scheduler.html) job once a week, after the reporting deadline of the week and after DHIS2 has updated its analytics tables:

![Weekly outbreak alerts job](https://zatosource-production.b-cdn.net/docs/gfx/dhis2/alerts-weekly-job-create.webp?v=1791212100)

Dashboard menu: Scheduler > Config

## Next {#next}

[Thresholds](https://zato.io/docs/dev/healthcare/dhis2/outbreak-alerts/thresholds.html) checks each series against the rule of its disease.

## See also {#see-also}

- [Setup](https://zato.io/docs/dev/healthcare/dhis2/outbreak-alerts/setup.html) - The DHIS2 Analytics connection and alerts.ini
- [Calling REST APIs](https://zato.io/docs/dev/rest/calling-apis.html) - Query parameters, payloads and response objects
- [Scheduler](https://zato.io/docs/dev/examples/scheduler.html) - Interval-based jobs

## Learn more {#learn-more}

- [Healthcare interface engine](https://zato.io/docs/dev/healthcare/) - Clinical messages, FHIR, conversion and operations
- [HL7 v2 parsing](https://zato.io/docs/dev/healthcare/hl7/v2/parsing/) - Messages as typed objects, with field access and validation
- [MLLP channels](https://zato.io/docs/dev/healthcare/hl7v2/mllp/) - Receiving and sending HL7 v2 over MLLP sockets
- [FHIR integrations](https://zato.io/docs/dev/healthcare/hl7/fhir/) - Read and write FHIR resources, with paths, bundles and extensions
- [HL7 v2 to FHIR](https://zato.io/docs/dev/healthcare/hl7/to-fhir/) - Converting v2 messages into FHIR bundles, codes and references included
- [EDIFACT](https://zato.io/docs/dev/healthcare/edifact/) - Parsing interchanges, dialects and the transports they arrive on
- [Transformation](https://zato.io/docs/dev/healthcare/transformation/) - One message in, another standard out, in ordinary Python
- [Audit log](https://zato.io/docs/dev/healthcare/audit-log.html) - Every message with its acknowledgment, searchable by patient identifier
- [AI in clinical interfaces](https://zato.io/docs/dev/healthcare/ai/) - Services calling LLMs and AI agents calling clinical services as tools
