Table of Contents

Getting started

Install the package:

dotnet add package Cavok

Parse a METAR

Metar.Parse returns a Metar record. Every group is a typed property; groups that occur more than once, such as clouds or runway visual ranges, are lists.

Metar metar = Metar.Parse("METAR EHAM 211125Z 24012G25KT 200V280 9999 -SHRA FEW012 BKN030CB 12/09 Q1013 TEMPO 4000 SHRA");

Console.WriteLine(metar.Station);                // EHAM
Console.WriteLine(metar.Wind?.Direction);        // 240
Console.WriteLine(metar.Wind?.Gust?.Value);      // 25
Console.WriteLine(metar.Visibility?.Meters);     // 10000 (9999 means 10 km or more)
Console.WriteLine(metar.Clouds[1].Type);         // Cumulonimbus
Console.WriteLine(metar.Pressure?.Hectopascals); // 1013
Console.WriteLine(metar.FlightCategory);         // Mvfr
Console.WriteLine(metar.Trends[0].Kind);         // Temporary

Describe it

Console.WriteLine(metar.Describe(Language.English));
Console.WriteLine(metar.Describe(Language.Dutch));

Parse a TAF

Taf.Parse returns the base forecast and a list of change groups, each with its own ForecastConditions.

Taf taf = Taf.Parse("TAF EHAM 210440Z 2106/2212 27005KT 9999 FEW035 BECMG 2106/2109 31011KT PROB30 TEMPO 2114/2118 TSRA");

foreach (TafChange change in taf.Changes)
{
    Console.WriteLine($"{change.Kind} {change.Probability} {change.Period?.From} {change.Conditions.Wind?.Direction}");
}

Console.WriteLine(taf.Describe(Language.English));

Lenient and strict parsing

Parse never throws for bad content. Whatever can be understood is returned and every problem is listed in Diagnostics. ParseStrict throws a CavokParseException when there is at least one error; warnings are allowed.

try
{
    Metar.ParseStrict("METAR EHAM 211125Z 24012KT 2400O Q1013");
}
catch (CavokParseException exception)
{
    Console.WriteLine(exception.Diagnostics[0].Describe(Language.Dutch));
    // ongeldige zichtgroep "2400O"; verwacht 4 cijfers (bijv. 0800, 9999)
}

Day and time

Reports only contain the day of the month. DayTime.ToDateTimeOffset picks the month and year closest to a reference moment, typically when the report was received:

// Reports only contain the day of the month; resolve it against the moment the report was received.
DateTimeOffset observed = metar.Time!.Value.ToDateTimeOffset(new DateTimeOffset(2026, 9, 21, 11, 40, 0, TimeSpan.Zero));
Console.WriteLine(observed.ToString("u", System.Globalization.CultureInfo.InvariantCulture)); // 2026-09-21 11:25:00Z