diff --git a/YamlDotNet.Benchmark/Program.cs b/YamlDotNet.Benchmark/Program.cs
index 9fc2ebd9a..8b88132dc 100644
--- a/YamlDotNet.Benchmark/Program.cs
+++ b/YamlDotNet.Benchmark/Program.cs
@@ -1,4 +1,11 @@
-using BenchmarkDotNet.Running;
+using System.Globalization;
+using BenchmarkDotNet.Running;
using YamlDotNet.Benchmark;
+using YamlDotNet.Core;
+using YamlDotNet.Core.Events;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.NamingConventions;
-BenchmarkSwitcher.FromAssembly(typeof(YamlStreamBenchmark).Assembly).Run(args);
+var dateTimeOffset = new DateTimeOffset(new DateTime(2017, 1, 2, 3, 4, 5), new TimeSpan(-6, 0, 0));
+Console.WriteLine(dateTimeOffset.ToString("MM/dd/yyyy HH:mm:ss zzz", CultureInfo.InvariantCulture));
+Console.WriteLine(dateTimeOffset.ToString("O", CultureInfo.InvariantCulture));
diff --git a/YamlDotNet.Samples/UseTypeConverters.cs b/YamlDotNet.Samples/UseTypeConverters.cs
new file mode 100644
index 000000000..8459428be
--- /dev/null
+++ b/YamlDotNet.Samples/UseTypeConverters.cs
@@ -0,0 +1,56 @@
+// This file is part of YamlDotNet - A .NET library for YAML.
+// Copyright (c) Antoine Aubry and contributors
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xunit.Abstractions;
+using YamlDotNet.Samples.Helpers;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.Converters;
+
+namespace YamlDotNet.Samples
+{
+ public class UseTypeConverters
+ {
+ ITestOutputHelper output;
+
+ public UseTypeConverters(ITestOutputHelper output)
+ {
+ this.output = output;
+ }
+
+ [Sample(
+ Description = "Shows how to deserialize objects with a type converter",
+ DisplayName = "Type Converters")]
+ public void Main()
+ {
+ var serializer = new SerializerBuilder()
+ .WithTypeConverter(new DateTimeOffsetConverter())
+ .Build();
+ var o = new { Hello = new DateTimeOffset(DateTime.Now, new TimeSpan(-6, 0, 0)) };
+ var yaml = serializer.Serialize(o);
+ output.WriteLine(yaml);
+ }
+ }
+}
diff --git a/YamlDotNet.Test/Serialization/DateTimeOffsetConverterTests.cs b/YamlDotNet.Test/Serialization/DateTimeOffsetConverterTests.cs
new file mode 100644
index 000000000..8bfbb2222
--- /dev/null
+++ b/YamlDotNet.Test/Serialization/DateTimeOffsetConverterTests.cs
@@ -0,0 +1,144 @@
+// This file is part of YamlDotNet - A .NET library for YAML.
+// Copyright (c) Antoine Aubry and contributors
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System;
+using System.Globalization;
+using FakeItEasy;
+using FluentAssertions;
+using Xunit;
+using YamlDotNet.Core;
+using YamlDotNet.Core.Events;
+using YamlDotNet.Serialization;
+using YamlDotNet.Serialization.Converters;
+
+namespace YamlDotNet.Test.Serialization
+{
+ ///
+ /// This represents the test entity for the class.
+ ///
+ public class DateTimeOffsetConverterTests
+ {
+ private readonly DateTimeOffset _expected = new DateTimeOffset(new DateTime(2017, 1, 2, 3, 4, 5), new TimeSpan(-6, 0, 0));
+ ///
+ /// Tests whether the Accepts() method should return expected result or not.
+ ///
+ /// to check.
+ /// Expected result.
+ [Theory]
+ [InlineData(typeof(DateTimeOffset), true)]
+ [InlineData(typeof(string), false)]
+ public void AcceptsTypeReturns(Type type, bool expected)
+ {
+ var converter = new DateTimeOffsetConverter(CultureInfo.InvariantCulture);
+
+ var result = converter.Accepts(type);
+
+ result.Should().Be(expected);
+ }
+
+ [Fact]
+ public void InvalidFormatThrowsException()
+ {
+ var yaml = "2019-01-01";
+
+ var parser = A.Fake();
+ A.CallTo(() => parser.Current).ReturnsLazily(() => new Scalar(yaml));
+
+ var converter = new DateTimeOffsetConverter(CultureInfo.InvariantCulture);
+
+ Action action = () => { converter.ReadYaml(parser, typeof(DateTimeOffset)); };
+
+ action.ShouldThrow();
+ }
+
+ [Fact]
+ public void ValidYamlReturnsDateTimeOffsetDefaultFormat()
+ {
+ var yaml = "2017-01-02T03:04:05.0000000-06:00";
+
+ var parser = A.Fake();
+ A.CallTo(() => parser.Current).ReturnsLazily(() => new Scalar(yaml));
+ var converter = new DateTimeOffsetConverter(CultureInfo.InvariantCulture);
+ var actual = converter.ReadYaml(parser, typeof(DateTimeOffset));
+ Assert.Equal(_expected, actual);
+ }
+
+ [Fact]
+ public void ValidYamlReturnsDateTimeOffsetAdditionalFormats()
+ {
+ var yaml = "01/02/2017 03:04:05 -06:00";
+
+ var parser = A.Fake();
+ A.CallTo(() => parser.Current).ReturnsLazily(() => new Scalar(yaml));
+
+ var converter = new DateTimeOffsetConverter(
+ CultureInfo.InvariantCulture,
+ ScalarStyle.Any,
+ DateTimeStyles.None,
+ "O",
+ "MM/dd/yyyy HH:mm:ss zzz");
+
+ converter.ReadYaml(parser, typeof(DateTimeOffset));
+ var actual = converter.ReadYaml(parser, typeof(DateTimeOffset));
+ Assert.Equal(_expected, actual);
+ }
+
+ [Fact]
+ public void ShouldSerializeRoundTripWithDefaults()
+ {
+ var converter = new DateTimeOffsetConverter(CultureInfo.InvariantCulture);
+ var serializer = new SerializerBuilder().WithTypeConverter(converter).Build();
+ var actual = serializer.Serialize(new Test { X = _expected }).NormalizeNewLines();
+ var expected = "X: 2017-01-02T03:04:05.0000000-06:00\r\n".NormalizeNewLines();
+ Assert.Equal(actual, expected);
+ }
+
+ [Fact]
+ public void ShouldSerializeWithCustomFormat()
+ {
+ var converter = new DateTimeOffsetConverter(
+ CultureInfo.InvariantCulture,
+ ScalarStyle.Any,
+ DateTimeStyles.None,
+ "MM/dd/yyyy HH:mm:ss zzz");
+
+ var serializer = new SerializerBuilder().WithTypeConverter(converter).Build();
+ var actual = serializer.Serialize(new Test { X = _expected }).NormalizeNewLines();
+ var expected = "X: 01/02/2017 03:04:05 -06:00\r\n".NormalizeNewLines();
+ Assert.Equal(actual, expected);
+ }
+
+ [Fact]
+ public void ShouldSerializeAndRespectQuotingStyle()
+ {
+ var converter = new DateTimeOffsetConverter(CultureInfo.InvariantCulture, ScalarStyle.DoubleQuoted);
+ var serializer = new SerializerBuilder().WithTypeConverter(converter).Build();
+ var actual = serializer.Serialize(new Test { X = _expected }).NormalizeNewLines();
+ var expected = "X: \"2017-01-02T03:04:05.0000000-06:00\"\r\n".NormalizeNewLines();
+ Assert.Equal(actual, expected);
+ }
+
+ private class Test
+ {
+ public DateTimeOffset X { get; set; }
+ }
+ }
+}
diff --git a/YamlDotNet/Serialization/Converters/DateTimeOffsetConverter.cs b/YamlDotNet/Serialization/Converters/DateTimeOffsetConverter.cs
new file mode 100644
index 000000000..81f7c51a8
--- /dev/null
+++ b/YamlDotNet/Serialization/Converters/DateTimeOffsetConverter.cs
@@ -0,0 +1,102 @@
+// This file is part of YamlDotNet - A .NET library for YAML.
+// Copyright (c) Antoine Aubry and contributors
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of
+// this software and associated documentation files (the "Software"), to deal in
+// the Software without restriction, including without limitation the rights to
+// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+// of the Software, and to permit persons to whom the Software is furnished to do
+// so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+using System;
+using System.Globalization;
+using System.Linq;
+using YamlDotNet.Core;
+using YamlDotNet.Core.Events;
+
+namespace YamlDotNet.Serialization.Converters
+{
+ ///
+ /// Converts the object to a string representation
+ /// To use this converter, call WithTypeConverter(new DateTimeOffsetConverter()) on the
+ /// or .
+ ///
+ public class DateTimeOffsetConverter : IYamlTypeConverter
+ {
+ private readonly IFormatProvider provider;
+ private readonly ScalarStyle style;
+ private readonly DateTimeStyles dateStyle;
+ private readonly string[] formats;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// instance. Default value is .
+ /// If true, will use double quotes when writing the value to the stream.
+ ///
+ /// List of date/time formats for parsing. Default value is "O".
+ /// On deserializing, all formats in the list are used for conversion, while on serializing, the first format in the list is used.
+ public DateTimeOffsetConverter(
+ IFormatProvider? provider = null,
+ ScalarStyle style = ScalarStyle.Any,
+ DateTimeStyles dateStyle = DateTimeStyles.None,
+ params string[] formats)
+ {
+ this.provider = provider ?? CultureInfo.InvariantCulture;
+ this.style = style;
+ this.dateStyle = dateStyle;
+ this.formats = formats.DefaultIfEmpty("O").ToArray();
+ }
+
+ ///
+ /// Gets a value indicating whether the current converter supports converting the specified type.
+ ///
+ /// to check.
+ /// Returns True, if the current converter supports; otherwise returns False.
+ public bool Accepts(Type type)
+ {
+ return type == typeof(DateTimeOffset);
+ }
+
+ ///
+ /// Reads an object's state from a YAML parser.
+ ///
+ /// instance.
+ /// to convert.
+ /// Returns the instance converted.
+ /// On deserializing, all formats in the list are used for conversion.
+ public object ReadYaml(IParser parser, Type type)
+ {
+ var value = parser.Consume().Value;
+ var result = DateTimeOffset.ParseExact(value, formats, provider, dateStyle);
+
+ return result;
+ }
+
+ ///
+ /// Writes the specified object's state to a YAML emitter.
+ ///
+ /// instance.
+ /// Value to write.
+ /// to convert.
+ /// On serializing, the first format in the list is used.
+ public void WriteYaml(IEmitter emitter, object? value, Type type)
+ {
+ var dt = (DateTimeOffset)value!;
+ var formatted = dt.ToString(formats.First(), this.provider); // Always take the first format of the list.
+
+ emitter.Emit(new Scalar(AnchorName.Empty, TagName.Empty, formatted, style, true, false));
+ }
+ }
+}