Skip to content

Time Series Providers – Guide & Recipes

A compact, developer-friendly map of all Time Series providers and how to wire and use them with the same service surface.


See also (deep dives)


Pick the right provider

Provider Read/Write Grouped IDs you pass Best for Notes
MCLite – DB (Provider.MCLite.TimeSeriesRepository) R/W /group/sub/Name Operational stores in MC/Lite (PG/SQL/SQLite) Raw/Blob storage, flags, aggregation (incl. ensembles), window deletes
MCLite – from Spreadsheet (Provider.MCLite.TimeSeriesFromSpreadsheetRepository) Read-only Spreadsheet=/calc/Book.xlsx;Timeseries=/out/Name[;TrimBlanks=true] Compositions & quick calcs in Excel Fills Data sheet, recalculates, reads Output named series
MIKECore – dfs0 (grouped) (Provider.MIKECore.Dfs0GroupedTimeSeriesRepository) R/W path\file.dfs0;ItemName Many .dfs0 under a root Update rewrites multi-item files; Remove deletes file when last item
MIKECore – dfs0 (single file) (Provider.MIKECore.Dfs0TimeSeriesRepository) R/W 3(name:WL)[eum:eumIWaterLevel] or WaterLevel One .dfs0 at a time SetValues only when file has one item
MIKECore – dfs2 / dfsu Read-only key=value;... (XY / LatLon / Polygon / ElementId) Extract point/area series from gridded files dfs2 supports True-North reprojection; dfsu supports 3D LayerNumber
MIKECloud (Provider.MIKECloud.GroupedTimeSeriesRepository) R/W /Sub1/Sub2/Dataset/SeriesName Cloud datasets Creates subprojects; dataset must exist; update is delete+recreate
MIKE1D results (Provider.MIKE1D.ResultFileGroupedTimeSeriesRepository) Read-only Group/Run/File.res1d/Type;Quantity;Id[;chainage] .res1d/.res11 runs Node/Reach/Catchment; shared time axis
USGS DV (Provider.USGS.TimeSeriesRepository) Read-only USGS:Site:Param:Stat Observed daily values Returns qualifiers as flags; EUM metadata mapped

All providers plug into DHI.Services.TimeSeries services, so your calling code stays the same.


Wire it in ~90 seconds

MCLite (database-backed)

using DHI.Services.TimeSeries;
using DHI.Services.Provider.MCLite;

var repo = new TimeSeriesRepository("database=mc2014.2"); // PG/SQL/SQLite via keys
var svc  = new TimeSeriesService<string,double>(repo);    // grouped & updatable
ServiceLocator.Register(svc, "mc-ts");                    // {connectionId}

MIKECore dfs0 (grouped)

using DHI.Services.Provider.MIKECore;
var repo = new Dfs0GroupedTimeSeriesRepository(@"C:\data"); // root with .dfs0 files
ServiceLocator.Register(new TimeSeriesService<string,double>(repo), "dfs0-grouped");

MIKECloud

using DHI.Services.Provider.MIKECloud;
var repo = new GroupedTimeSeriesRepository("apiKey=...;projectId=...;environment=Prod");
ServiceLocator.Register(new GroupedUpdatableTimeSeriesService<string,double>(repo), "mc-cloud");

Prefer the Connections module in hosts; see JSON examples in §7.


IDs & groups — cheat sheet

  • FullName: "/group/sub/Name" (no trailing slash for series).
  • Group tree modifiers (suffix on group string): ;nonrecursive · ;groupsonly · ;nonrecursive;groupsonly

Provider-specific IDs

  • MCLite DB: /Hydro/Basin/Stage
  • MCLite from Spreadsheet: Spreadsheet=/calc/Book.xlsx;Timeseries=/out/Stage;TrimBlanks=true
  • dfs0 (grouped): data\stations\a.dfs0;WaterLevel
  • dfs0 (single file): 3(name:WaterLevel)[eum:eumIWaterLevel] or WaterLevel
  • dfs2: Item=HS;Latitude=55.0;Longitude=12.0 or Item=HS;PolygonLngLat=lon,lat,...;AreaStatistic=Average
  • dfsu: Item=Salinity;X=700000;Y=6175000[;LayerNumber=3]
  • MIKECloud: /Ops/North/Telemetry/WaterLevel (dataset is the group; last segment is name)
  • USGS: USGS:11458000:00060:00003

Common tasks (works the same across R/W providers)

var id  = "/import/Well7/Head";

// Create if missing
if (!svc.Contains(id)) {
  var ts = new TimeSeries<string,double>(id, "Head", "/import/Well7") {
    Quantity = "WaterLevel", Unit = "m", DataType = TimeSeriesDataType.Instantaneous
  };
  svc.Add(ts);
}

// Write (dedup per second by default on MCLite DB)
var data = new TimeSeriesData<double>();
data.Append(DateTime.UtcNow.AddHours(-1), 1.23);
data.Append(DateTime.UtcNow,             1.31);
svc.SetValues(id, data);

// Read window
var window = svc.GetValues(id, DateTime.UtcNow.AddDays(-7), DateTime.UtcNow).Value;

// Aggregate
var avg7d = svc.GetAggregatedValue(id, AggregationType.Average,
                                   DateTime.UtcNow.AddDays(-7), DateTime.UtcNow).Value;

Flags (MCLite DB, MIKECloud returns null flags):

var flagged = new TimeSeriesDataWFlag<double,int?>();
flagged.Append(t0, 1.23, 101);
flagged.Append(t1, null, null);
svc.SetValues(id, flagged); // preserves duplicates exactly (no dedup pass)

Provider-specific quick recipes

dfs0 (grouped): replace an item inside a multi-item file

var id = @"data\stations\a.dfs0;WaterLevel";
var entity = repo.Get(id).Value;
entity.Data = window;          // your new values
repo.Update(entity);           // rewrites the file

dfs2: True-North reprojection

var u = repo.GetValues("Item=U;UItem=U;VItem=V;Latitude=55.676;Longitude=12.568").Value; // True East/West
var d = repo.GetValues("Item=CurrentDirection;Latitude=55.676;Longitude=12.568;ReprojectNorth=true").Value;

MCLite from Spreadsheet: compute series

Spreadsheet has Definitions, Data, Output (row 0 names every second col).

var sid = "Spreadsheet=/calc/RatingCurves.xlsx;Timeseries=/computed/FlowAtS2;TrimBlanks=true";
var vals = svc.GetValues(sid, DateTime.Parse("2024-01-01"), DateTime.Parse("2024-02-01")).Value;

MIKECloud: safe replace of a window

repo.RemoveValues("/Hydro/Observations/WaterLevel", t0, t1);
repo.SetValues("/Hydro/Observations/WaterLevel", newData);

Web API pairing (Connections JSON samples)

{
  "$type": "System.Collections.Generic.Dictionary`2[[System.String, mscorlib],[DHI.Services.IConnection, DHI.Services]], mscorlib",

  "mc-ws1": {
    "$type": "DHI.Services.TimeSeries.WebApi.GroupedUpdatableTimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "database=mc2014.2",
    "RepositoryType": "DHI.Services.Provider.MCLite.TimeSeriesRepository, DHI.Services.Provider.MCLite",
    "Name": "MCLite DB time series",
    "Id": "mc-ws1"
  },

  "dfs0-grouped": {
    "$type": "DHI.Services.TimeSeries.WebApi.GroupedDiscreteTimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "[AppData]dfs0",
    "RepositoryType": "DHI.Services.Provider.MIKECore.Dfs0GroupedTimeSeriesRepository, DHI.Services.Provider.MIKECore",
    "Name": "dfs0 grouped",
    "Id": "dfs0-grouped"
  },

  "dfs2": {
    "$type": "DHI.Services.TimeSeries.WebApi.TimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "C:\\Data\\R20141001.dfs2",
    "RepositoryType": "DHI.Services.Provider.MIKECore.Dfs2TimeSeriesRepository, DHI.Services.Provider.MIKECore",
    "Name": "dfs2",
    "Id": "dfs2"
  },

  "dfsu": {
    "$type": "DHI.Services.TimeSeries.WebApi.TimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "C:\\Data\\mesh.dfsu",
    "RepositoryType": "DHI.Services.Provider.MIKECore.DfsuTimeSeriesRepository, DHI.Services.Provider.MIKECore",
    "Name": "dfsu",
    "Id": "dfsu"
  },

  "mc-cloud": {
    "$type": "DHI.Services.TimeSeries.WebApi.GroupedUpdatableTimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "apiKey=[env:MIKECLOUD_APIKEY];projectId=[env:MIKECLOUD_PROJECT];environment=Prod",
    "RepositoryType": "DHI.Services.Provider.MIKECloud.GroupedTimeSeriesRepository, DHI.Services.Provider.MIKECloud",
    "Name": "MIKECloud time series",
    "Id": "mc-cloud"
  },

  "usgs-dv": {
    "$type": "DHI.Services.TimeSeries.WebApi.TimeSeriesServiceConnection, DHI.Services.TimeSeries.WebApi",
    "ConnectionString": "https://waterservices.usgs.gov/nwis/dv/?startDT=2024-01-01&endDT=2024-12-31",
    "RepositoryType": "DHI.Services.Provider.USGS.TimeSeriesRepository, DHI.Services.Provider.USGS",
    "Name": "USGS Daily Values",
    "Id": "usgs-dv"
  }
}

URL encoding tips

  • dfs0 ids with ; must be encoded if you expose the id directly; most APIs use FullName (file/item) in routes.
  • dfs2/dfsu key=value;... ids should be URL-encoded as a single token.

Foot-guns & pro tips

MCLite DB

  • Default dedup is PerSecond. To preserve duplicates, send ITimeSeriesDataWFlag<double,int?> (even with null flags).
  • Raw vs. Blob storage is per series (storage_type=0|1). Blob writes merge by period (hour/day/week/month/year).
  • RemoveValues also purges flags in the window (when flags table exists).
  • SQL Server floor: times below SqlDateTime.MinValue are bumped.
  • RemoveByGroup deletes entities then group tree.

MCLite from Spreadsheet

  • Requires sheets Definitions, Data, Output (row 0 headers every second column).
  • Each call clears Data and recalculates the workbook. Read-only by design.
  • Debug=true writes a temp snapshot after calc.

MIKECore dfs0

  • Single-file repo SetValues works only when the file has a single item.
  • For multi-item files use grouped repo + Update.
  • Equidistant files require equidistant input on SetValues.
  • RemoveValues is not implemented.

dfs2/dfsu

  • Choose exactly one locator: ElementId or XY or Lat/Lon or Polygon.
  • dfs2: UItem/VItem reprojection returns a True-East/True-North component; ReprojectNorth=true fixes direction items.
  • dfsu 3D: add LayerNumber.

MIKECloud

  • Provider creates subprojects, not datasets — provision datasets first.
  • Update path is delete+recreate; for values, prefer RemoveValues + SetValues.

USGS

  • Daily values only. Qualifiers come back as flags; texts live in metadata.

Quick reference

Need… Use… Snippet
Create + write to DB MCLite DB svc.Add(ts); svc.SetValues(id, data);
Replace series inside .dfs0 with other items present dfs0 (grouped) var e = repo.Get(id).Value; e.Data = data; repo.Update(e);
Extract point series from grid dfs2/dfsu repo.GetValues("Item=HS;Latitude=55.0;Longitude=12.0")
Compose series in Excel MCLite from Spreadsheet svc.GetValues("Spreadsheet=...;Timeseries=/out/Name")
Cloud dataset MIKECloud repo.SetValues("/Path/Dataset/Name", data)
Observations (DV) USGS svc.GetValues("USGS:11458000:00060:00003")

Bottom line: choose a provider by where your data lives (DB, files, cloud, external), then code once against TimeSeriesService. When in doubt, start with MCLite DB for CRUD + analytics, use dfs0/dfs2/dfsu for MIKE files, MIKECloud for platform datasets, USGS for read-only observations, and Spreadsheet when domain logic lives in Excel.