The usage of ICustomDiagnosticMessage here is non-essential - ToDiagnosticString
doesn't actually get called by ToString() in this case, due to JsonFormatter code. It was
intended to make it clearer that it *did* have a custom format... but then arguably I should
do the same for Value, Struct, Any etc.
Moving some of the code out of JsonFormatter and into Duration/Timestamp/FieldMask likewise
feels somewhat nice, somewhat nasty... basically there are JSON-specific bits of formatting, but
also domain-specific bits of computation. <sigh>
Thoughts welcome.
/// Converts a duration specified in seconds/nanoseconds to a string.
/// </summary>
/// <remarks>
/// If the value is a normalized duration in the range described in <c>duration.proto</c>,
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
/// </remarks>
/// <param name="seconds">Seconds portion of the duration.</param>
/// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
/// Converts a timestamp specified in seconds/nanoseconds to a string.
/// </summary>
/// <remarks>
/// If the value is a normalized duration in the range described in <c>field_mask.proto</c>,
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
/// </remarks>
/// <param name="paths">Paths in the field mask</param>
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>
/// Converts a timestamp specified in seconds/nanoseconds to a string.
/// </summary>
/// <remarks>
/// If the value is a normalized duration in the range described in <c>timestamp.proto</c>,
/// <paramref name="diagnosticOnly"/> is ignored. Otherwise, if the parameter is <c>true</c>,
/// a JSON object with a warning is returned; if it is <c>false</c>, an <see cref="InvalidOperationException"/> is thrown.
/// </remarks>
/// <param name="seconds">Seconds portion of the duration.</param>
/// <param name="nanoseconds">Nanoseconds portion of the duration.</param>
/// <param name="diagnosticOnly">Determines the handling of non-normalized values</param>
/// <exception cref="InvalidOperationException">The represented duration is invalid, and <paramref name="diagnosticOnly"/> is <c>false</c>.</exception>