├── .editorconfig ├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ └── publish_nuget.yml ├── .gitignore ├── CODEOWNERS ├── Directory.Build.props ├── LICENSE ├── MessagePack.NodaTime.Tests ├── ContractlessTests.cs ├── Helpers │ └── TestTools.cs ├── Init │ └── MessagePackTestInit.cs ├── MessagePack.NodaTime.Tests.csproj ├── NodaTimeTests │ ├── DurationMessagePackFormatterTest.cs │ ├── InstantMessagePackFormatterTest.cs │ ├── LocalDateMessagePackFormatterTest.cs │ ├── LocalDateTimeMessagePackFormatterTest.cs │ ├── LocalTimeMessagePackTest.cs │ ├── OffsetDateTimeMessagePackFormatterTest.cs │ ├── OffsetMessagePackFormatterTest.cs │ ├── PeriodMessagePackFormatterTest.cs │ └── ZonedDateTimeMessagePackFormatterTest.cs ├── SourceGeneratedContractTests.cs ├── SystemDateTimeTests.cs └── TimestampTests │ └── TimestampTests.cs ├── MessagePack.NodaTime ├── DurationMessagePackFormatter.cs ├── InstantMessagePackFormatter.cs ├── LocalDateMessagePackFormatter.cs ├── LocalDateTimeAsDateTimeMessagePackFormatter.cs ├── LocalTimeMessagePackFormatter.cs ├── MessagePack.NodaTime.csproj ├── NodatimeMessagePackExtensionTypeCode.cs ├── NodatimeResolver.cs ├── OffsetDateTimeMessagePackFormatter.cs ├── OffsetMessagePackFormatter.cs ├── PeriodMessagePackFormatter.cs └── ZonedDateTimeMessagePackFormatter.cs ├── MessagePack.sln ├── MessagePack.sln.licenseheader ├── README.md ├── ark-dark.png ├── global.json └── renovate.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories 2 | root = true 3 | 4 | # C# files 5 | [*.cs] 6 | 7 | #### Core EditorConfig Options #### 8 | 9 | # Indentation and spacing 10 | indent_size = 4 11 | indent_style = space 12 | tab_width = 4 13 | 14 | # New line preferences 15 | end_of_line = crlf 16 | insert_final_newline = false 17 | 18 | #### .NET Coding Conventions #### 19 | 20 | # Organize usings 21 | dotnet_separate_import_directive_groups = true 22 | dotnet_sort_system_directives_first = false 23 | file_header_template = unset 24 | 25 | # this. and Me. preferences 26 | dotnet_style_qualification_for_event = false:silent 27 | dotnet_style_qualification_for_field = false:silent 28 | dotnet_style_qualification_for_method = false:silent 29 | dotnet_style_qualification_for_property = false:silent 30 | 31 | # Language keywords vs BCL types preferences 32 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 33 | dotnet_style_predefined_type_for_member_access = true:silent 34 | 35 | # Parentheses preferences 36 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 37 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 38 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 39 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 40 | 41 | # Modifier preferences 42 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 43 | 44 | # Expression-level preferences 45 | dotnet_style_coalesce_expression = true:suggestion 46 | dotnet_style_collection_initializer = true:suggestion 47 | dotnet_style_explicit_tuple_names = true:suggestion 48 | dotnet_style_null_propagation = true:suggestion 49 | dotnet_style_object_initializer = true:suggestion 50 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 51 | dotnet_style_prefer_auto_properties = true:silent 52 | dotnet_style_prefer_compound_assignment = true:suggestion 53 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 54 | dotnet_style_prefer_conditional_expression_over_return = true:silent 55 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 56 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 57 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 58 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 59 | dotnet_style_prefer_simplified_interpolation = true:suggestion 60 | 61 | # Field preferences 62 | dotnet_style_readonly_field = true:suggestion 63 | 64 | # Parameter preferences 65 | dotnet_code_quality_unused_parameters = all:suggestion 66 | 67 | #### C# Coding Conventions #### 68 | 69 | # var preferences 70 | csharp_style_var_elsewhere = false:silent 71 | csharp_style_var_for_built_in_types = false:silent 72 | csharp_style_var_when_type_is_apparent = false:silent 73 | 74 | # Expression-bodied members 75 | csharp_style_expression_bodied_accessors = true:silent 76 | csharp_style_expression_bodied_constructors = false:silent 77 | csharp_style_expression_bodied_indexers = true:silent 78 | csharp_style_expression_bodied_lambdas = true:silent 79 | csharp_style_expression_bodied_local_functions = false:silent 80 | csharp_style_expression_bodied_methods = false:silent 81 | csharp_style_expression_bodied_operators = false:silent 82 | csharp_style_expression_bodied_properties = true:silent 83 | 84 | # Pattern matching preferences 85 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 86 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 87 | csharp_style_prefer_switch_expression = true:suggestion 88 | 89 | # Null-checking preferences 90 | csharp_style_conditional_delegate_call = true:suggestion 91 | 92 | # Modifier preferences 93 | csharp_prefer_static_local_function = true:suggestion 94 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent 95 | 96 | # Code-block preferences 97 | csharp_prefer_braces = true:silent 98 | csharp_prefer_simple_using_statement = true:suggestion 99 | 100 | # Expression-level preferences 101 | csharp_prefer_simple_default_expression = true:suggestion 102 | csharp_style_deconstructed_variable_declaration = true:suggestion 103 | csharp_style_inlined_variable_declaration = true:suggestion 104 | csharp_style_pattern_local_over_anonymous_function = true:suggestion 105 | csharp_style_prefer_index_operator = true:suggestion 106 | csharp_style_prefer_range_operator = true:suggestion 107 | csharp_style_throw_expression = true:suggestion 108 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 109 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 110 | 111 | # 'using' directive preferences 112 | csharp_using_directive_placement = outside_namespace:silent 113 | 114 | #### C# Formatting Rules #### 115 | 116 | # New line preferences 117 | csharp_new_line_before_catch = true 118 | csharp_new_line_before_else = true 119 | csharp_new_line_before_finally = true 120 | csharp_new_line_before_members_in_anonymous_types = true 121 | csharp_new_line_before_members_in_object_initializers = true 122 | csharp_new_line_before_open_brace = all 123 | csharp_new_line_between_query_expression_clauses = true 124 | 125 | # Indentation preferences 126 | csharp_indent_block_contents = true 127 | csharp_indent_braces = false 128 | csharp_indent_case_contents = true 129 | csharp_indent_case_contents_when_block = true 130 | csharp_indent_labels = one_less_than_current 131 | csharp_indent_switch_labels = true 132 | 133 | # Space preferences 134 | csharp_space_after_cast = false 135 | csharp_space_after_colon_in_inheritance_clause = true 136 | csharp_space_after_comma = true 137 | csharp_space_after_dot = false 138 | csharp_space_after_keywords_in_control_flow_statements = true 139 | csharp_space_after_semicolon_in_for_statement = true 140 | csharp_space_around_binary_operators = before_and_after 141 | csharp_space_around_declaration_statements = false 142 | csharp_space_before_colon_in_inheritance_clause = true 143 | csharp_space_before_comma = false 144 | csharp_space_before_dot = false 145 | csharp_space_before_open_square_brackets = false 146 | csharp_space_before_semicolon_in_for_statement = false 147 | csharp_space_between_empty_square_brackets = false 148 | csharp_space_between_method_call_empty_parameter_list_parentheses = false 149 | csharp_space_between_method_call_name_and_opening_parenthesis = false 150 | csharp_space_between_method_call_parameter_list_parentheses = false 151 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false 152 | csharp_space_between_method_declaration_name_and_open_parenthesis = false 153 | csharp_space_between_method_declaration_parameter_list_parentheses = false 154 | csharp_space_between_parentheses = false 155 | csharp_space_between_square_brackets = false 156 | 157 | # Wrapping preferences 158 | csharp_preserve_single_line_blocks = true 159 | csharp_preserve_single_line_statements = true 160 | 161 | #### Naming styles #### 162 | 163 | # Naming rules 164 | 165 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = error 166 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 167 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 168 | 169 | dotnet_naming_rule.types_should_be_pascal_case.severity = error 170 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 171 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 172 | 173 | dotnet_naming_rule.private_method_should_be_begins_with__.severity = error 174 | dotnet_naming_rule.private_method_should_be_begins_with__.symbols = private_method 175 | dotnet_naming_rule.private_method_should_be_begins_with__.style = begins_with__ 176 | 177 | dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.severity = error 178 | dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.symbols = private_or_internal_field 179 | dotnet_naming_rule.private_or_internal_field_should_be_begins_with__.style = begins_with__ 180 | 181 | dotnet_naming_rule.private_properties_should_be_begins_with__.severity = error 182 | dotnet_naming_rule.private_properties_should_be_begins_with__.symbols = private_property 183 | dotnet_naming_rule.private_properties_should_be_begins_with__.style = begins_with__ 184 | 185 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = error 186 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 187 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 188 | 189 | # Symbol specifications 190 | 191 | dotnet_naming_symbols.interface.applicable_kinds = interface 192 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal 193 | dotnet_naming_symbols.interface.required_modifiers = 194 | 195 | dotnet_naming_symbols.private_method.applicable_kinds = method 196 | dotnet_naming_symbols.private_method.applicable_accessibilities = private 197 | dotnet_naming_symbols.private_method.required_modifiers = 198 | 199 | dotnet_naming_symbols.private_property.applicable_kinds = property 200 | dotnet_naming_symbols.private_property.applicable_accessibilities = private 201 | dotnet_naming_symbols.private_property.required_modifiers = 202 | 203 | dotnet_naming_symbols.private_or_internal_field.applicable_kinds = field 204 | dotnet_naming_symbols.private_or_internal_field.applicable_accessibilities = internal, private 205 | dotnet_naming_symbols.private_or_internal_field.required_modifiers = 206 | 207 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 208 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal 209 | dotnet_naming_symbols.types.required_modifiers = 210 | 211 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 212 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal 213 | dotnet_naming_symbols.non_field_members.required_modifiers = 214 | 215 | # Naming styles 216 | 217 | dotnet_naming_style.pascal_case.required_prefix = 218 | dotnet_naming_style.pascal_case.required_suffix = 219 | dotnet_naming_style.pascal_case.word_separator = 220 | dotnet_naming_style.pascal_case.capitalization = pascal_case 221 | 222 | dotnet_naming_style.begins_with_i.required_prefix = I 223 | dotnet_naming_style.begins_with_i.required_suffix = 224 | dotnet_naming_style.begins_with_i.word_separator = 225 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 226 | 227 | dotnet_naming_style.begins_with__.required_prefix = _ 228 | dotnet_naming_style.begins_with__.required_suffix = 229 | dotnet_naming_style.begins_with__.word_separator = 230 | dotnet_naming_style.begins_with__.capitalization = camel_case 231 | csharp_style_namespace_declarations = block_scoped:warning 232 | dotnet_diagnostic.CA1825.severity = warning 233 | dotnet_diagnostic.CA1841.severity = warning 234 | csharp_style_prefer_method_group_conversion = true:silent 235 | dotnet_diagnostic.CA1070.severity = warning 236 | dotnet_diagnostic.CA1001.severity = error 237 | dotnet_diagnostic.CA1309.severity = suggestion 238 | dotnet_diagnostic.CA1507.severity = warning 239 | dotnet_diagnostic.CA2016.severity = warning 240 | csharp_style_prefer_top_level_statements = true:silent 241 | csharp_style_prefer_null_check_over_type_check = true:warning 242 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 243 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 244 | csharp_style_prefer_tuple_swap = true:suggestion 245 | csharp_style_prefer_utf8_string_literals = true:suggestion 246 | dotnet_code_quality.ca1051.exclude_structs = true 247 | 248 | [*.{cs,vb}] 249 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 250 | tab_width = 4 251 | indent_size = 4 252 | end_of_line = crlf 253 | dotnet_style_coalesce_expression = true:suggestion 254 | dotnet_style_null_propagation = true:suggestion 255 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 256 | dotnet_style_prefer_auto_properties = true:silent 257 | dotnet_style_object_initializer = true:suggestion 258 | dotnet_style_collection_initializer = true:suggestion 259 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 260 | dotnet_diagnostic.CA1827.severity = error 261 | dotnet_diagnostic.CA1828.severity = warning 262 | dotnet_diagnostic.CA2000.severity = error 263 | dotnet_diagnostic.CA2012.severity = warning 264 | dotnet_diagnostic.CA1018.severity = warning 265 | dotnet_diagnostic.CA1041.severity = warning 266 | dotnet_diagnostic.CA1051.severity = warning 267 | dotnet_diagnostic.CA1061.severity = warning 268 | dotnet_diagnostic.CA1067.severity = warning 269 | dotnet_diagnostic.CA1068.severity = error 270 | dotnet_diagnostic.CA1069.severity = error 271 | dotnet_diagnostic.CA1304.severity = suggestion 272 | dotnet_diagnostic.CA1305.severity = suggestion 273 | dotnet_diagnostic.CA1310.severity = suggestion 274 | dotnet_diagnostic.CA1821.severity = error 275 | dotnet_diagnostic.CA1823.severity = error 276 | dotnet_diagnostic.CA1832.severity = warning 277 | dotnet_diagnostic.CA1833.severity = warning 278 | dotnet_diagnostic.CA1836.severity = error 279 | dotnet_diagnostic.CA1844.severity = warning 280 | dotnet_diagnostic.CA1847.severity = warning 281 | dotnet_diagnostic.CA2002.severity = error 282 | dotnet_diagnostic.CA2011.severity = warning 283 | dotnet_diagnostic.CA5350.severity = warning 284 | dotnet_diagnostic.CA5351.severity = error 285 | dotnet_diagnostic.CA5359.severity = warning 286 | dotnet_diagnostic.CA5379.severity = suggestion 287 | dotnet_diagnostic.CA5385.severity = warning 288 | dotnet_diagnostic.CA5397.severity = warning 289 | dotnet_diagnostic.CA1816.severity = warning 290 | dotnet_diagnostic.CA2201.severity = warning 291 | dotnet_diagnostic.CA2211.severity = warning 292 | dotnet_diagnostic.CA2215.severity = warning 293 | dotnet_diagnostic.CA2219.severity = warning 294 | dotnet_diagnostic.CA2242.severity = warning 295 | dotnet_diagnostic.CA2245.severity = error 296 | dotnet_style_readonly_field = true:suggestion 297 | dotnet_diagnostic.CA1063.severity = error 298 | dotnet_diagnostic.CA2213.severity = warning 299 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 300 | dotnet_style_explicit_tuple_names = true:suggestion 301 | dotnet_style_prefer_conditional_expression_over_return = true:silent 302 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 303 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 304 | dotnet_style_prefer_compound_assignment = true:suggestion 305 | dotnet_style_prefer_simplified_interpolation = true:suggestion 306 | dotnet_style_namespace_match_folder = true:suggestion 307 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 308 | dotnet_style_predefined_type_for_member_access = true:silent 309 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 310 | dotnet_diagnostic.CA1834.severity = warning 311 | dotnet_diagnostic.CA1835.severity = warning 312 | dotnet_diagnostic.CA1846.severity = warning 313 | dotnet_diagnostic.CA5360.severity = warning 314 | dotnet_diagnostic.CA5363.severity = warning 315 | dotnet_diagnostic.CA2250.severity = warning 316 | dotnet_diagnostic.CA2253.severity = warning 317 | [*.vb] 318 | dotnet_diagnostic.CA1047.severity = warning -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "nuget" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | ignore: 13 | - dependency-name: "*" 14 | update-types: ["version-update:semver-major"] 15 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '19 23 * * 5' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'csharp' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Use only 'java' to analyze code written in Java, Kotlin or both 38 | # Use only 'javascript' to analyze code written in JavaScript, TypeScript or both 39 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 40 | 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | # If you wish to specify custom queries, you can do so here or in a config file. 51 | # By default, queries listed here will override any specified in a config file. 52 | # Prefix the list here with "+" to use these queries and those in the config file. 53 | 54 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 55 | # queries: security-extended,security-and-quality 56 | 57 | - name: 'Install dotnet' 58 | uses: actions/setup-dotnet@v4 59 | with: 60 | global-json-file: global.json 61 | 62 | - name: 'Restore packages' 63 | run: dotnet restore 64 | 65 | - name: 'Build project' 66 | run: dotnet build --configuration Release 67 | 68 | - name: Perform CodeQL Analysis 69 | uses: github/codeql-action/analyze@v3 70 | with: 71 | category: "/language:${{matrix.language}}" 72 | -------------------------------------------------------------------------------- /.github/workflows/publish_nuget.yml: -------------------------------------------------------------------------------- 1 | name: "Deploy to NuGet" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | tags: 7 | - 'v[0-9]+\.[0-9]+\.[0-9]+' 8 | - 'v[0-9]+\.[0-9]+\.[0-9]+-beta[0-9][0-9]' 9 | pull_request: 10 | branches: [ master ] 11 | 12 | env: 13 | PACKAGE_OUTPUT_DIRECTORY: ${{ github.workspace }}\output 14 | NUGET_SOURCE_URL: 'https://api.nuget.org/v3/index.json' 15 | 16 | permissions: 17 | contents: read 18 | statuses: write 19 | checks: write 20 | 21 | jobs: 22 | build: 23 | name: 'Build' 24 | runs-on: 'windows-latest' 25 | steps: 26 | - name: 'Checkout' 27 | uses: actions/checkout@v4 28 | 29 | - name: 'Install dotnet' 30 | uses: actions/setup-dotnet@v4 31 | with: 32 | global-json-file: global.json 33 | 34 | - name: 'Restore packages' 35 | run: dotnet restore 36 | 37 | - name: 'Build project' 38 | run: dotnet build --no-restore --configuration Release 39 | 40 | - name: Test 41 | run: dotnet test --logger "trx;LogFileName=test-results.trx" --no-restore || true 42 | 43 | - name: Test Report 44 | uses: dorny/test-reporter@v1 45 | if: always() 46 | with: 47 | name: DotNET Tests 48 | path: "**/test-results.trx" 49 | reporter: dotnet-trx 50 | fail-on-error: true 51 | 52 | deploy: 53 | name: 'Nuget Push' 54 | runs-on: 'windows-latest' 55 | needs: build 56 | if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') 57 | 58 | steps: 59 | - name: 'Checkout' 60 | uses: actions/checkout@v4 61 | 62 | - name: 'Install dotnet' 63 | uses: actions/setup-dotnet@v4 64 | with: 65 | global-json-file: global.json 66 | 67 | - name: 'Get Version' 68 | id: version 69 | uses: battila7/get-version-action@v2 70 | 71 | - name: 'Pack project' 72 | run: dotnet pack --configuration Release --include-symbols -p:Version=${{ steps.version.outputs.version-without-v }} --output ${{ env.PACKAGE_OUTPUT_DIRECTORY }} 73 | # --no-build somehow cannot be used due to being needed: 74 | 75 | - name: 'Push package' 76 | run: dotnet nuget push ${{ env.PACKAGE_OUTPUT_DIRECTORY }}\*.nupkg -k ${{ secrets.NUGET_AUTH_TOKEN }} -s ${{ env.NUGET_SOURCE_URL }} 77 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | project.fragment.lock.json 46 | artifacts/ 47 | 48 | *_i.c 49 | *_p.c 50 | *_i.h 51 | *.ilk 52 | *.meta 53 | *.obj 54 | *.pch 55 | *.pdb 56 | *.pgc 57 | *.pgd 58 | *.rsp 59 | *.sbr 60 | *.tlb 61 | *.tli 62 | *.tlh 63 | *.tmp 64 | *.tmp_proj 65 | *.log 66 | *.vspscc 67 | *.vssscc 68 | .builds 69 | *.pidb 70 | *.svclog 71 | *.scc 72 | 73 | # Chutzpah Test files 74 | _Chutzpah* 75 | 76 | # Visual C++ cache files 77 | ipch/ 78 | *.aps 79 | *.ncb 80 | *.opendb 81 | *.opensdf 82 | *.sdf 83 | *.cachefile 84 | *.VC.db 85 | *.VC.VC.opendb 86 | 87 | # Visual Studio profiler 88 | *.psess 89 | *.vsp 90 | *.vspx 91 | *.sap 92 | 93 | # TFS 2012 Local Workspace 94 | $tf/ 95 | 96 | # Guidance Automation Toolkit 97 | *.gpState 98 | 99 | # ReSharper is a .NET coding add-in 100 | _ReSharper*/ 101 | *.[Rr]e[Ss]harper 102 | *.DotSettings.user 103 | 104 | # JustCode is a .NET coding add-in 105 | .JustCode 106 | 107 | # TeamCity is a build add-in 108 | _TeamCity* 109 | 110 | # DotCover is a Code Coverage Tool 111 | *.dotCover 112 | 113 | # NCrunch 114 | _NCrunch_* 115 | .*crunch*.local.xml 116 | nCrunchTemp_* 117 | 118 | # MightyMoose 119 | *.mm.* 120 | AutoTest.Net/ 121 | 122 | # Web workbench (sass) 123 | .sass-cache/ 124 | 125 | # Installshield output folder 126 | [Ee]xpress/ 127 | 128 | # DocProject is a documentation generator add-in 129 | DocProject/buildhelp/ 130 | DocProject/Help/*.HxT 131 | DocProject/Help/*.HxC 132 | DocProject/Help/*.hhc 133 | DocProject/Help/*.hhk 134 | DocProject/Help/*.hhp 135 | DocProject/Help/Html2 136 | DocProject/Help/html 137 | 138 | # Click-Once directory 139 | publish/ 140 | 141 | # Publish Web Output 142 | *.[Pp]ublish.xml 143 | *.azurePubxml 144 | # TODO: Comment the next line if you want to checkin your web deploy settings 145 | # but database connection strings (with potential passwords) will be unencrypted 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 150 | # checkin your Azure Web App publish settings, but sensitive information contained 151 | # in these scripts will be unencrypted 152 | PublishScripts/ 153 | 154 | # NuGet Packages 155 | *.nupkg 156 | # The packages folder can be ignored because of Package Restore 157 | **/packages/* 158 | # except build/, which is used as an MSBuild target. 159 | !**/packages/build/ 160 | # Uncomment if necessary however generally it will be regenerated when needed 161 | #!**/packages/repositories.config 162 | # NuGet v3's project.json files produces more ignoreable files 163 | *.nuget.props 164 | *.nuget.targets 165 | 166 | # Microsoft Azure Build Output 167 | csx/ 168 | *.build.csdef 169 | 170 | # Microsoft Azure Emulator 171 | ecf/ 172 | rcf/ 173 | 174 | # Windows Store app package directories and files 175 | AppPackages/ 176 | BundleArtifacts/ 177 | Package.StoreAssociation.xml 178 | _pkginfo.txt 179 | 180 | # Visual Studio cache files 181 | # files ending in .cache can be ignored 182 | *.[Cc]ache 183 | # but keep track of directories ending in .cache 184 | !*.[Cc]ache/ 185 | 186 | # Others 187 | ClientBin/ 188 | ~$* 189 | *~ 190 | *.dbmdl 191 | *.dbproj.schemaview 192 | *.jfm 193 | *.pfx 194 | *.publishsettings 195 | node_modules/ 196 | orleans.codegen.cs 197 | 198 | # Since there are multiple workflows, uncomment next line to ignore bower_components 199 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 200 | #bower_components/ 201 | 202 | # RIA/Silverlight projects 203 | Generated_Code/ 204 | 205 | # Backup & report files from converting an old project file 206 | # to a newer Visual Studio version. Backup files are not needed, 207 | # because we have git ;-) 208 | _UpgradeReport_Files/ 209 | Backup*/ 210 | UpgradeLog*.XML 211 | UpgradeLog*.htm 212 | 213 | # SQL Server files 214 | *.mdf 215 | *.ldf 216 | 217 | # Business Intelligence projects 218 | *.rdl.data 219 | *.bim.layout 220 | *.bim_*.settings 221 | 222 | # Microsoft Fakes 223 | FakesAssemblies/ 224 | 225 | # GhostDoc plugin setting file 226 | *.GhostDoc.xml 227 | 228 | # Node.js Tools for Visual Studio 229 | .ntvs_analysis.dat 230 | 231 | # Visual Studio 6 build log 232 | *.plg 233 | 234 | # Visual Studio 6 workspace options file 235 | *.opt 236 | 237 | # Visual Studio LightSwitch build output 238 | **/*.HTMLClient/GeneratedArtifacts 239 | **/*.DesktopClient/GeneratedArtifacts 240 | **/*.DesktopClient/ModelManifest.xml 241 | **/*.Server/GeneratedArtifacts 242 | **/*.Server/ModelManifest.xml 243 | _Pvt_Extensions 244 | 245 | # Paket dependency manager 246 | .paket/paket.exe 247 | paket-files/ 248 | 249 | # FAKE - F# Make 250 | .fake/ 251 | 252 | # JetBrains Rider 253 | .idea/ 254 | *.sln.iml 255 | 256 | # CodeRush 257 | .cr/ 258 | 259 | # Python Tools for Visual Studio (PTVS) 260 | __pycache__/ 261 | *.pyc -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @ARKlab/maintainers 2 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0;netstandard2.0;netstandard2.1; 5 | 12 6 | true 7 | 1591 8 | enable 9 | 10 | 11 | 12 | 13 | 14 | /subscriptions/dummy 15 | 16 | 17 | 18 | true 19 | false 20 | false 21 | false 22 | 23 | https://github.com/ARKlab/MessagePack 24 | MIT 25 | 26 | ark-dark.png 27 | https://github.com/ARKlab/MessagePack 28 | 29 | 30 | ARK Labs 31 | Copyright (C) 2023 ARK S.r.l 32 | 33 | true 34 | snupkg 35 | 36 | 37 | 38 | 39 | true 40 | 41 | 42 | true 43 | 44 | portable 45 | 46 | 47 | 48 | 49 | all 50 | runtime; build; native; contentfiles; analyzers 51 | 52 | 53 | 54 | all 55 | runtime; build; native; contentfiles; analyzers 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | all 67 | runtime; build; native; contentfiles; analyzers 68 | 69 | 70 | 71 | all 72 | runtime; build; native; contentfiles; analyzers 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 ARK LTD 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/ContractlessTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Resolvers; 5 | using NodaTime; 6 | using System; 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using Xunit; 11 | 12 | namespace MessagePack.NodaTime.Tests 13 | { 14 | public class LDT 15 | { 16 | public LocalDateTime ldt { get; set; } 17 | } 18 | 19 | [Collection("ResolverCollection")] 20 | public class ContractlessTests 21 | { 22 | [Fact] 23 | public void AnonType() 24 | { 25 | var o = new { Ldt = LocalDateTime.FromDateTime(DateTime.Now) }; 26 | var bin = MessagePackSerializer.Serialize(o); 27 | var res = MessagePackSerializer.Deserialize(bin); 28 | 29 | var abc = ((IEnumerable)res).Cast>().First().Value; 30 | 31 | Assert.Equal(o.Ldt.ToDateTimeUnspecified(), abc); // in DateTime format due to 'abc' being DateTime object 32 | } 33 | 34 | [Fact] 35 | public void AnonTypeWithClassProperty() 36 | { 37 | var o = new { ldt = LocalDateTime.FromDateTime(DateTime.Now) }; 38 | var bin = MessagePackSerializer.Serialize(o); 39 | var res = MessagePackSerializer.Deserialize(bin); 40 | 41 | Assert.Equal(o.ldt, res.ldt); 42 | } 43 | 44 | [Fact(Skip = "object cannot be serialized due to DateTime part of Nodatime type")] 45 | public void ObjectToDynamic() 46 | { 47 | object o = new ZonedDateTime(); 48 | var bin = MessagePackSerializer.Serialize(o); 49 | var res = MessagePackSerializer.Deserialize(bin); 50 | 51 | Assert.Equal(o, res); 52 | } 53 | 54 | [Fact] 55 | public void ObjectToLDT() 56 | { 57 | object o = new LocalDateTime(); 58 | var bin = MessagePackSerializer.Serialize(o); 59 | var res = MessagePackSerializer.Deserialize(bin); 60 | 61 | Assert.Equal(o, res); 62 | } 63 | 64 | [Fact] 65 | public void ObjectToInstant() 66 | { 67 | object o = new Instant(); 68 | var bin = MessagePackSerializer.Serialize(o); 69 | var res = MessagePackSerializer.Deserialize(bin); 70 | 71 | Assert.Equal(o, res); 72 | } 73 | 74 | [Fact] 75 | public void DynamicToLDT() 76 | { 77 | dynamic d = new LocalDate(); 78 | var bin = MessagePackSerializer.Serialize(d); 79 | var res = MessagePackSerializer.Deserialize(bin); 80 | Assert.Equal(d, res); 81 | } 82 | 83 | [Fact(Skip = "cannot be deserialized as dynamic")] 84 | public void ZonedDTToDynamic() 85 | { 86 | var d = new ZonedDateTime(); 87 | var bin = MessagePackSerializer.Serialize(d); 88 | var res = MessagePackSerializer.Deserialize(bin); 89 | 90 | Assert.Equal(d, res); 91 | } 92 | 93 | [Fact] 94 | public void ObjectWithNonGeneric() 95 | { 96 | object o = new LocalDateTime(); 97 | var bin = MessagePackSerializer.Serialize(o.GetType(), o); 98 | var res = MessagePackSerializer.Deserialize(o.GetType(), bin); 99 | 100 | Assert.Equal(o, res); 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/Helpers/TestTools.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using Microsoft.VisualStudio.TestTools.UnitTesting; 5 | using System; 6 | 7 | namespace MessagePack.NodaTime.Tests.Helpers 8 | { 9 | static class TestTools 10 | { 11 | public static T Convert(T value) 12 | { 13 | return MessagePackSerializer.Deserialize(MessagePackSerializer.Serialize(value)); 14 | } 15 | 16 | public static void ThrowsInner(Func testCode) where T : Exception 17 | { 18 | try 19 | { 20 | testCode.Invoke(); 21 | } 22 | catch(Exception ex) 23 | { 24 | var currex = ex; 25 | 26 | while (currex != null) 27 | { 28 | if (currex is T) 29 | { 30 | return; 31 | } 32 | 33 | currex = currex.InnerException; 34 | } 35 | } 36 | 37 | Assert.Fail($"Extention of type {typeof(T).Name} is not throwed"); 38 | 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/Init/MessagePackTestInit.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Resolvers; 5 | using Xunit; 6 | 7 | namespace MessagePack.NodaTime.Tests.Utils 8 | { 9 | public class ResolverFixture 10 | { 11 | public ResolverFixture() 12 | { 13 | var resolver = CompositeResolver.Create(new[] { 14 | BuiltinResolver.Instance, 15 | AttributeFormatterResolver.Instance, 16 | SourceGeneratedFormatterResolver.Instance, 17 | NodatimeResolver.Instance, 18 | DynamicEnumAsStringResolver.Instance, 19 | ContractlessStandardResolver.Instance 20 | } 21 | ); 22 | 23 | var options = MessagePackSerializerOptions.Standard.WithResolver(resolver); 24 | 25 | // pass options to every time or set as default 26 | MessagePackSerializer.DefaultOptions = options; 27 | } 28 | } 29 | [CollectionDefinition("ResolverCollection")] 30 | public class ResolverCollection : ICollectionFixture 31 | { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/MessagePack.NodaTime.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 3.9.1 18 | 19 | 20 | 3.9.1 21 | 22 | 23 | 2.9.3 24 | 25 | 26 | 3.1.1 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | all 29 | 30 | 31 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/DurationMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class DurationMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void DurationTest() 16 | { 17 | var d = Duration.FromDays(1); 18 | Assert.Equal(TestTools.Convert(d), d); 19 | } 20 | 21 | [Fact] 22 | public void DurationArrayTest() 23 | { 24 | var p = new Duration[] 25 | { 26 | Duration.FromDays(1), 27 | Duration.FromNanoseconds(100), 28 | }; 29 | Assert.Equal(TestTools.Convert(p), p); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/InstantMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class InstantMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void InstantValueTest() 16 | { 17 | Instant inst = Instant.FromDateTimeUtc(DateTime.UtcNow); 18 | Assert.Equal(TestTools.Convert(inst), inst); 19 | } 20 | 21 | [Fact] 22 | public void NullableInstantValueTest() 23 | { 24 | Instant? inst = null; 25 | Assert.Equal(TestTools.Convert(inst), inst); 26 | } 27 | 28 | [Fact] 29 | public void InstantArrayTest() 30 | { 31 | Instant[] inst = 32 | { Instant.FromDateTimeUtc(DateTime.UtcNow.AddHours(13)), 33 | Instant.FromDateTimeUtc(DateTime.UtcNow.AddMinutes(54)), 34 | Instant.FromDateTimeUtc(DateTime.UtcNow.AddYears(1)), 35 | Instant.FromDateTimeUtc(DateTime.UtcNow.AddSeconds(33)), 36 | Instant.FromDateTimeUtc(DateTime.UtcNow), 37 | }; 38 | Assert.Equal(TestTools.Convert(inst), inst); 39 | } 40 | 41 | [Fact] 42 | public void NullableInstantArrayTest() 43 | { 44 | Instant?[] inst = new Instant?[] { 45 | null, 46 | null, 47 | null, 48 | null, 49 | null 50 | }; 51 | Assert.Equal(TestTools.Convert(inst), inst); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/LocalDateMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class LocalDateMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void LocalDateTest() 16 | { 17 | LocalDate ld = LocalDate.FromDateTime(DateTime.Now); 18 | Assert.Equal(TestTools.Convert(ld), ld); 19 | } 20 | 21 | [Fact] 22 | public void NullableLocalDateTest() 23 | { 24 | LocalDate? ld = null; 25 | Assert.Equal(TestTools.Convert(ld), ld); 26 | } 27 | 28 | [Fact] 29 | public void LocalDateArrayTest() 30 | { 31 | LocalDate[] ld = 32 | { LocalDate.FromDateTime(DateTime.Now), 33 | LocalDate.FromDateTime(new DateTime()), 34 | LocalDate.FromDateTime(DateTime.Now.AddTicks(500)), 35 | LocalDate.FromDateTime(DateTime.Now.AddMonths(10)), 36 | LocalDate.FromDateTime(new DateTime(2010,10,10)) 37 | }; 38 | Assert.Equal(TestTools.Convert(ld), ld); 39 | } 40 | 41 | [Fact] 42 | public void NullableLocalDateArrayTest() 43 | { 44 | LocalDate?[] ld = new LocalDate?[] { 45 | null, 46 | null, 47 | null, 48 | null, 49 | null 50 | }; 51 | Assert.Equal(TestTools.Convert(ld), ld); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/LocalDateTimeMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class LocalDateTimeAsDateTimeMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void LocalDateTimeAsDateTimeTest() 16 | { 17 | LocalDateTime ldt = LocalDateTime.FromDateTime(DateTime.Now); 18 | Assert.Equal(TestTools.Convert(ldt), ldt); 19 | } 20 | 21 | [Fact] 22 | public void NullableLocalDateTimeAsDateTimeTest() 23 | { 24 | LocalDateTime? ldt = null; 25 | Assert.Equal(TestTools.Convert(ldt), ldt); 26 | } 27 | 28 | [Fact] 29 | public void LocalDateTimeArrayTest() 30 | { 31 | LocalDateTime[] ldt = 32 | { LocalDateTime.FromDateTime(DateTime.Now.AddDays(3)), 33 | LocalDateTime.FromDateTime(new DateTime()), 34 | LocalDateTime.FromDateTime(DateTime.Now.AddTicks(500)), 35 | LocalDateTime.FromDateTime(DateTime.Now), 36 | LocalDateTime.FromDateTime(new DateTime(2010,10,10)) 37 | }; 38 | Assert.Equal(TestTools.Convert(ldt), ldt); 39 | } 40 | 41 | [Fact] 42 | public void NullableLocalDateTimeArrayTest() 43 | { 44 | LocalDateTime?[] ldt = new LocalDateTime?[] { 45 | null, 46 | null, 47 | null, 48 | null, 49 | null 50 | }; 51 | Assert.Equal(TestTools.Convert(ldt), ldt); 52 | } 53 | 54 | [Fact] 55 | public void LocalDateTimeToLocalDateWithTimeLoss() 56 | { 57 | LocalDateTime ldt = new LocalDateTime(2018, 5, 15, 1, 0, 0).PlusTicks(1); 58 | var bin = MessagePackSerializer.Serialize(ldt); 59 | 60 | TestTools.ThrowsInner(() => 61 | (MessagePackSerializer.Deserialize(bin))); 62 | } 63 | 64 | [Fact] 65 | public void LocalDateTimeToLocalDateTimeWithNanosecondsLoss() 66 | { 67 | //nanosecond accuracy lost in datetime conversion --> ReadMe 68 | LocalDateTime ldt = new LocalDateTime(2018, 5, 15, 0, 0, 0).PlusNanoseconds(1); 69 | var bin = MessagePackSerializer.Serialize(ldt); 70 | var res = TestTools.Convert(ldt); 71 | 72 | Assert.NotEqual(ldt, res); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/LocalTimeMessagePackTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using Xunit; 7 | 8 | namespace MessagePack.NodaTime.Tests 9 | { 10 | [Collection("ResolverCollection")] 11 | public class LocalTimeMessagePackFormatterTest 12 | { 13 | [Fact] 14 | public void LocalTimeTest() 15 | { 16 | LocalTime t = LocalTime.FromSecondsSinceMidnight(1); 17 | Assert.Equal(TestTools.Convert(t), t); 18 | } 19 | 20 | [Fact] 21 | public void NullableLocalTimeTest() 22 | { 23 | LocalTime? t = null; 24 | Assert.Equal(TestTools.Convert(t), t); 25 | } 26 | 27 | [Fact] 28 | public void LocalTimeArrayTest() 29 | { 30 | LocalTime[] lt = 31 | { LocalTime.FromTicksSinceMidnight(4000), 32 | LocalTime.FromSecondsSinceMidnight(10000), 33 | LocalTime.FromHourMinuteSecondTick(20,10,1,13), 34 | new LocalTime(), 35 | LocalTime.FromSecondsSinceMidnight(1) 36 | }; 37 | Assert.Equal(TestTools.Convert(lt), lt); 38 | } 39 | 40 | [Fact] 41 | public void NullableLocalTimeArrayTest() 42 | { 43 | LocalTime?[] lt = new LocalTime?[] { 44 | null, 45 | null, 46 | null, 47 | null, 48 | null 49 | }; 50 | Assert.Equal(TestTools.Convert(lt), lt); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/OffsetDateTimeMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class OffsetDateTimeMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void OffsetDateTimeTest() 16 | { 17 | OffsetDateTime offSet = new OffsetDateTime().PlusHours(3).WithOffset(Offset.FromHours(6)); 18 | Assert.Equal(TestTools.Convert(offSet), offSet); 19 | } 20 | 21 | [Fact] 22 | public void NullableOffsetDateTimeTest() 23 | { 24 | OffsetDateTime? offSet = null; 25 | Assert.Equal(TestTools.Convert(offSet), offSet); 26 | } 27 | 28 | [Fact] 29 | public void OffsetDateTimeArrayTest() 30 | { 31 | OffsetDateTime[] offSet = new OffsetDateTime[] 32 | { new OffsetDateTime().WithOffset(Offset.FromHours(2)), 33 | new OffsetDateTime(), 34 | new OffsetDateTime(LocalDateTime.FromDateTime(DateTime.UtcNow).PlusNanoseconds(200), Offset.FromHours(1)), 35 | new OffsetDateTime().PlusMinutes(10), 36 | new OffsetDateTime().PlusHours(3).WithOffset(Offset.FromHours(6)) 37 | }; 38 | 39 | var aaa = TestTools.Convert(offSet); 40 | 41 | Assert.Equal(TestTools.Convert(offSet), offSet); 42 | } 43 | 44 | [Fact] 45 | public void NullableOffsetDateTimeArrayTest() 46 | { 47 | OffsetDateTime?[] offSet = new OffsetDateTime?[] { 48 | null, 49 | null, 50 | null, 51 | null, 52 | null 53 | }; 54 | Assert.Equal(TestTools.Convert(offSet), offSet); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/OffsetMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using Xunit; 7 | 8 | namespace MessagePack.NodaTime.Tests 9 | { 10 | [Collection("ResolverCollection")] 11 | public class OffsetMessagePackFormatterTest 12 | { 13 | [Fact] 14 | public void OffsetTest() 15 | { 16 | Offset offSet = Offset.FromHours(1); 17 | Assert.Equal(TestTools.Convert(offSet), offSet); 18 | } 19 | 20 | [Fact] 21 | public void NullableOffsetTest() 22 | { 23 | Offset? offSet = null; 24 | Assert.Equal(TestTools.Convert(offSet), offSet); 25 | } 26 | 27 | [Fact] 28 | public void OffsetArrayTest() 29 | { 30 | Offset[] offSet = new Offset[] 31 | { Offset.FromHoursAndMinutes(1, 3), 32 | Offset.FromSeconds(80), 33 | Offset.FromMilliseconds(200), 34 | Offset.FromHours(3), 35 | Offset.FromNanoseconds(99) 36 | }; 37 | Assert.Equal(TestTools.Convert(offSet), offSet); 38 | } 39 | 40 | [Fact] 41 | public void NullableOffsetArrayTest() 42 | { 43 | Offset?[] offSet = new Offset?[] { 44 | null, 45 | null, 46 | null, 47 | null, 48 | null 49 | }; 50 | Assert.Equal(TestTools.Convert(offSet), offSet); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/PeriodMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class PeriodMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void PeriodTest() 16 | { 17 | Period p = Period.FromDays(1); 18 | Assert.Equal(TestTools.Convert(p), p); 19 | } 20 | 21 | [Fact] 22 | public void PeriodArrayTest() 23 | { 24 | var pp = new PeriodBuilder 25 | { 26 | Years = DateTime.UtcNow.Year, 27 | Months = DateTime.UtcNow.Month, 28 | Weeks = 4, 29 | Days = DateTime.UtcNow.Day, 30 | Hours = new DateTime().Hour, 31 | Minutes = DateTime.UtcNow.Minute, 32 | Seconds = new DateTime().Second, 33 | Milliseconds = DateTime.UtcNow.Millisecond, 34 | Ticks = DateTime.Now.Ticks, 35 | Nanoseconds = DateTime.UtcNow.Ticks / 100, 36 | }.Build(); 37 | 38 | var pp1 = new PeriodBuilder 39 | { 40 | Years = DateTime.UtcNow.Year, 41 | Months = DateTime.UtcNow.Month, 42 | Weeks = 4, 43 | Days = new DateTime().Day 44 | }.Build(); 45 | 46 | Period[] p = new Period[] 47 | { Period.FromYears(1), 48 | pp, 49 | Period.FromDays(1), 50 | Period.FromNanoseconds(5), 51 | pp1 52 | }; 53 | Assert.Equal(TestTools.Convert(p), p); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/NodaTimeTests/ZonedDateTimeMessagePackFormatterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class ZonedDateTimeMessagePackFormatterTest 13 | { 14 | [Fact] 15 | public void ZonedDateTimeTest() 16 | { 17 | Instant inst = Instant.FromDateTimeUtc(DateTime.UtcNow); 18 | ZonedDateTime zoned = new ZonedDateTime(inst, DateTimeZone.Utc); 19 | Assert.Equal(TestTools.Convert(zoned), zoned); 20 | } 21 | 22 | [Fact] 23 | public void NullableZonedDateTimeTest() 24 | { 25 | ZonedDateTime? zoned = null; 26 | Assert.Equal(TestTools.Convert(zoned), zoned); 27 | } 28 | 29 | [Fact] 30 | public void ZonedDateTimeArrayTest() 31 | { 32 | Instant inst = Instant.FromDateTimeUtc(DateTime.UtcNow); 33 | LocalDateTime ldt = LocalDateTime.FromDateTime(DateTime.Now); 34 | ZonedDateTime[] zoned = new ZonedDateTime[] 35 | { new ZonedDateTime(inst, DateTimeZone.Utc), 36 | new ZonedDateTime(inst, DateTimeZone.Utc), 37 | new ZonedDateTime(inst, DateTimeZone.Utc), 38 | new ZonedDateTime(inst, DateTimeZone.Utc), 39 | new ZonedDateTime(inst, DateTimeZone.Utc) 40 | }; 41 | Assert.Equal(TestTools.Convert(zoned), zoned); 42 | } 43 | 44 | [Fact] 45 | public void NullableZonedDateTimeArrayTest() 46 | { 47 | ZonedDateTime?[] zoned = new ZonedDateTime?[] { 48 | null, 49 | null, 50 | null, 51 | null, 52 | null 53 | }; 54 | Assert.Equal(TestTools.Convert(zoned), zoned); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/SourceGeneratedContractTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack; 5 | using MessagePack.Resolvers; 6 | using NodaTime; 7 | using System; 8 | using System.Collections; 9 | using System.Collections.Generic; 10 | using System.Linq; 11 | using Xunit; 12 | 13 | namespace MessagePack.NodaTime.Tests 14 | { 15 | [MessagePackObject] 16 | public record MyClass 17 | { 18 | [Key(0)] 19 | public LocalDateTime LocalDateTime { get; set; } = LocalDateTime.FromDateTime(DateTime.Now); 20 | 21 | [Key(1)] 22 | public Instant Instant { get; set; } = Instant.FromDateTimeUtc(DateTime.UtcNow); 23 | 24 | [Key(2)] 25 | public Period Period { get; set; } = Period.Zero; 26 | 27 | [Key(3)] 28 | public LocalDate LocalDate { get; set; } = LocalDate.FromDateTime(DateTime.Now.Date); 29 | 30 | [Key(4)] 31 | public OffsetDateTime OffsetDateTime { get; set; } = OffsetDateTime.FromDateTimeOffset(DateTimeOffset.Now); 32 | 33 | [Key(5)] 34 | public Duration Duration { get; set; } = Duration.Zero; 35 | 36 | [Key(6)] 37 | public ZonedDateTime ZonedDateTime { get; set; } = ZonedDateTime.FromDateTimeOffset(DateTimeOffset.Now); 38 | } 39 | 40 | [Collection("ResolverCollection")] 41 | public class SourceGeneratedContractTests 42 | { 43 | [Fact] 44 | public void Roundtrip() 45 | { 46 | var o = new MyClass { LocalDateTime = LocalDateTime.FromDateTime(DateTime.Now) }; 47 | var bin = MessagePackSerializer.Serialize(o); 48 | var res = MessagePackSerializer.Deserialize(bin); 49 | 50 | Assert.Equal(o, res); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/SystemDateTimeTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using System.Collections; 8 | using System.Collections.Generic; 9 | using Xunit; 10 | 11 | namespace MessagePack.NodaTime.Tests 12 | { 13 | [Collection("ResolverCollection")] 14 | public class SystemDateTimeTests 15 | { 16 | [Fact] 17 | public void LocalDateTimeToDateTime() 18 | { 19 | DateTime dt = new DateTime(2000, 1, 1, 1, 22, 33); 20 | LocalDateTime ldt = LocalDateTime.FromDateTime(dt); 21 | 22 | var localDateTimeBinary = MessagePackSerializer.Serialize(ldt); 23 | var resultDateTime = MessagePackSerializer.Deserialize(localDateTimeBinary); 24 | 25 | Assert.Equal(dt, resultDateTime); 26 | } 27 | 28 | [Fact] 29 | public void DateTimeToLocalDateTime() 30 | { 31 | var ldt = new LocalDateTime(2018, 5, 15, 0, 0); 32 | var dt = DateTime.SpecifyKind(ldt.ToDateTimeUnspecified(), DateTimeKind.Utc); 33 | 34 | var bin = MessagePackSerializer.Serialize(dt); 35 | var res = MessagePackSerializer.Deserialize(bin); 36 | 37 | Assert.Equal(ldt, res); 38 | } 39 | 40 | [Fact] 41 | public void LocalDateTimeToLocalDate() 42 | { 43 | LocalDateTime ldt = new LocalDateTime(2016, 08, 21, 0, 0, 0, 0); 44 | 45 | var bin = MessagePackSerializer.Serialize(ldt); 46 | var res = MessagePackSerializer.Deserialize(bin); 47 | 48 | Assert.Equal(ldt.Date, res); 49 | } 50 | 51 | [Fact] 52 | public void LocalDateTimeToLocalDateFailing() 53 | { 54 | LocalDateTime ldt = new LocalDateTime(2016, 08, 21, 0, 0, 0, 0).PlusNanoseconds(100); 55 | 56 | var bin = MessagePackSerializer.Serialize(ldt); 57 | Assert.Throws(() => MessagePackSerializer.Deserialize(bin)); 58 | } 59 | 60 | [Fact] 61 | public void DateTimeToLocalDate() 62 | { 63 | DateTime dt = new DateTime(1986, 12, 11, 0, 0, 0); 64 | 65 | var bin = MessagePackSerializer.Serialize(dt); 66 | var res = MessagePackSerializer.Deserialize(bin); 67 | 68 | Assert.Equal(dt.Date, res.ToDateTimeUnspecified()); 69 | } 70 | 71 | [Fact] 72 | public void LocalDateToLocalDateTime() 73 | { 74 | LocalDate ld = new LocalDate(2000, 1, 1); 75 | 76 | LocalDateTime ldt = LocalDateTime.FromDateTime(new DateTime(2000, 1, 1)); 77 | 78 | var bin = MessagePackSerializer.Serialize(ld); 79 | var res = MessagePackSerializer.Deserialize(bin); 80 | 81 | Assert.Equal(ldt, res); 82 | } 83 | 84 | [Fact] 85 | public void DateTimeToLocalDateWithPrecisionLoss() 86 | { 87 | DateTime dt = new DateTime(2000, 1, 1, 0, 0, 1); 88 | 89 | TestTools.ThrowsInner(() => 90 | (MessagePackSerializer.Deserialize(MessagePackSerializer.Serialize(dt)))); 91 | } 92 | 93 | [Fact] 94 | public void LocalDateTimeToLocalDateWithPrecisionLoss() 95 | { 96 | LocalDateTime ldt = new LocalDateTime(2000, 1, 1, 0, 0, 0, 1); 97 | 98 | TestTools.ThrowsInner(() => 99 | (MessagePackSerializer.Deserialize(MessagePackSerializer.Serialize(ldt)))); 100 | } 101 | 102 | [Fact(Skip = "Fails due to Time being converted to UTC, goes back an hour")] 103 | public void DateTimeToLocalDateTime1() 104 | { 105 | var ldt = new LocalDateTime(2018, 5, 15, 0, 0, 0); 106 | var dt = new DateTime(2018, 5, 15, 0, 0, 0); 107 | 108 | var bin = MessagePackSerializer.Serialize(dt); 109 | var res = MessagePackSerializer.Deserialize(bin); 110 | 111 | Assert.Equal(ldt, res); 112 | } 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /MessagePack.NodaTime.Tests/TimestampTests/TimestampTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.NodaTime.Tests.Helpers; 5 | using NodaTime; 6 | using System; 7 | using Xunit; 8 | 9 | namespace MessagePack.NodaTime.Tests.TimestampTests 10 | { 11 | [Collection("ResolverCollection")] 12 | public class TimestampTests1 13 | { 14 | [Fact] 15 | public void LocalDateTimeTimestamp96_1() 16 | { 17 | LocalDateTime ldt1 = new LocalDateTime(0001, 01, 01, 00, 00, 00); 18 | 19 | var ts96_1 = MessagePackSerializer.Serialize(ldt1); // timestamp96 (byte[15]) 20 | Assert.Equal(15, ts96_1.Length); 21 | } 22 | 23 | [Fact] 24 | public void LocalDateTimeTimestamp96_2() 25 | { 26 | LocalDateTime ldt2 = new LocalDateTime(9999, 01, 01, 00, 00, 00); 27 | 28 | var ts96_2 = MessagePackSerializer.Serialize(ldt2); // timestamp96 (byte[15]) 29 | Assert.Equal(15, ts96_2.Length); 30 | } 31 | 32 | [Fact] 33 | public void LocalDateTimeTimestamp64() 34 | { 35 | LocalDateTime ldt3 = new LocalDateTime(2108, 01, 01, 00, 00, 00); 36 | 37 | var ts64 = MessagePackSerializer.Serialize(ldt3); // timestamp64 (byte[10]) 38 | Assert.Equal(10, ts64.Length); 39 | } 40 | 41 | [Fact] 42 | public void LocalDateTimeTimestamp32() 43 | { 44 | LocalDateTime ldt4 = new LocalDateTime(1971, 01, 01, 22, 45, 56); 45 | 46 | var ts32 = MessagePackSerializer.Serialize(ldt4); // timestamp32 (byte[6]) 47 | Assert.Equal(6, ts32.Length); 48 | } 49 | } 50 | 51 | [Collection("ResolverCollection")] 52 | public class TimestampTests2 53 | { 54 | [Fact] 55 | public void LocalDateTimestamp96_1() 56 | { 57 | LocalDate ld1 = new LocalDate(0001, 01, 01); 58 | 59 | var ts96_1 = MessagePackSerializer.Serialize(ld1); // timestamp96 (byte[15]) 60 | Assert.Equal(15, ts96_1.Length); 61 | } 62 | 63 | [Fact] 64 | public void LocalDateTimestamp96_2() 65 | { 66 | LocalDate ld2 = new LocalDate(9999, 01, 01); 67 | 68 | var ts96_2 = MessagePackSerializer.Serialize(ld2); // timestamp96 (byte[15]) 69 | Assert.Equal(15, ts96_2.Length); 70 | } 71 | 72 | [Fact] 73 | public void LocalDateTimestamp64() 74 | { 75 | LocalDate ld3 = new LocalDate(2108, 01, 01); 76 | 77 | var ts64 = MessagePackSerializer.Serialize(ld3); // timestamp64 (byte[10]) 78 | Assert.Equal(10, ts64.Length); 79 | } 80 | 81 | [Fact] 82 | public void LocalDateTimestamp32() 83 | { 84 | LocalDate ld4 = new LocalDate(1971, 01, 01); 85 | 86 | var ts32 = MessagePackSerializer.Serialize(ld4); // timestamp32 (byte[6]) 87 | Assert.Equal(6, ts32.Length); 88 | } 89 | } 90 | 91 | [Collection("ResolverCollection")] 92 | public class TimestampTests3 93 | { 94 | [Fact] 95 | public void InstantTimestamp96_1() 96 | { 97 | var dt = new DateTime(0001, 01, 01, 00, 00, 00).ToUniversalTime(); 98 | Instant inst1 = Instant.FromDateTimeUtc(dt); 99 | 100 | var ts96_1 = MessagePackSerializer.Serialize(inst1); // timestamp96 (byte[15]) 101 | Assert.Equal(15, ts96_1.Length); 102 | } 103 | 104 | [Fact] 105 | public void InstantTimestamp96_2() 106 | { 107 | var dt = new DateTime(9999, 01, 01, 00, 00, 00).ToUniversalTime(); 108 | Instant inst2 = Instant.FromDateTimeUtc(dt); 109 | 110 | var ts96_2 = MessagePackSerializer.Serialize(inst2); // timestamp96 (byte[15]) 111 | Assert.Equal(15, ts96_2.Length); 112 | } 113 | 114 | [Fact] 115 | public void InstantTimestamp64() 116 | { 117 | var dt = new DateTime(2108, 01, 01, 00, 00, 00).ToUniversalTime(); 118 | Instant inst3 = Instant.FromDateTimeUtc(dt); 119 | 120 | var ts64 = MessagePackSerializer.Serialize(inst3); // timestamp64 (byte[10]) 121 | Assert.Equal(10, ts64.Length); 122 | } 123 | 124 | [Fact] 125 | public void InstantTimestamp32() 126 | { 127 | var dt = new DateTime(1971, 01, 01, 00, 00, 00).ToUniversalTime(); 128 | Instant inst4 = Instant.FromDateTimeUtc(dt); 129 | 130 | var ts32 = MessagePackSerializer.Serialize(inst4); // timestamp32 (byte[6]) 131 | Assert.Equal(6, ts32.Length); 132 | } 133 | } 134 | 135 | [Collection("ResolverCollection")] 136 | public class TimestampTests4 137 | { 138 | [Fact] 139 | public void LocalDateTimestamp32WithNanos() 140 | { 141 | //only changes to timestamp64 if nanoseconds are 100 or more 142 | LocalDateTime ld1 = new LocalDateTime(1971, 01, 01, 00, 00, 00, 00).PlusNanoseconds(100); 143 | var ts32_64 = MessagePackSerializer.Serialize(ld1); // a = timestamp64 (byte[10]) 144 | 145 | Assert.Equal(10, ts32_64.Length); 146 | } 147 | 148 | [Fact] 149 | public void LocalDateTimestamp32WithNanosTruncating() 150 | { 151 | //only changes to timestamp64 if nanoseconds are 100 or more 152 | LocalDateTime ld1 = new LocalDateTime(1971, 01, 01, 00, 00, 00, 00).PlusNanoseconds(99); 153 | 154 | var ts32_64 = MessagePackSerializer.Serialize(ld1); // a != timestamp64 (byte[10]) 155 | Assert.Equal(6, ts32_64.Length); 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/DurationMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | 6 | using NodaTime; 7 | using NodaTime.Text; 8 | 9 | using System; 10 | 11 | namespace MessagePack.NodaTime 12 | { 13 | [ExcludeFormatterFromSourceGeneratedResolver] 14 | public sealed class DurationAsNanosecondsMessagePackFormatter : IMessagePackFormatter 15 | { 16 | public static readonly DurationAsNanosecondsMessagePackFormatter Instance = new DurationAsNanosecondsMessagePackFormatter(); 17 | 18 | public Duration Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 19 | { 20 | var s = reader.ReadInt64(); 21 | 22 | return Duration.FromNanoseconds(s); 23 | } 24 | 25 | public void Serialize(ref MessagePackWriter writer, Duration value, MessagePackSerializerOptions options) 26 | { 27 | writer.Write(value.ToInt64Nanoseconds()); 28 | } 29 | } 30 | 31 | public sealed class DurationAsBclTicksMessagePackFormatter : IMessagePackFormatter 32 | { 33 | public static readonly DurationAsBclTicksMessagePackFormatter Instance = new DurationAsBclTicksMessagePackFormatter(); 34 | 35 | public Duration Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 36 | { 37 | var s = reader.ReadInt64(); 38 | 39 | return Duration.FromTicks(s); 40 | } 41 | 42 | public void Serialize(ref MessagePackWriter writer, Duration value, MessagePackSerializerOptions options) 43 | { 44 | writer.Write(value.BclCompatibleTicks); 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /MessagePack.NodaTime/InstantMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | 7 | namespace MessagePack.NodaTime 8 | { 9 | public sealed class InstantMessagePackFormatter : IMessagePackFormatter 10 | { 11 | public static readonly InstantMessagePackFormatter Instance = new InstantMessagePackFormatter(); 12 | 13 | public Instant Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 14 | { 15 | var dt = reader.ReadDateTime(); 16 | return Instant.FromDateTimeUtc(dt); 17 | } 18 | 19 | public void Serialize(ref MessagePackWriter writer, Instant value, MessagePackSerializerOptions options) 20 | { 21 | writer.Write(value.ToDateTimeUtc()); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /MessagePack.NodaTime/LocalDateMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | using System; 7 | 8 | namespace MessagePack.NodaTime 9 | { 10 | // Not interoperable 11 | [ExcludeFormatterFromSourceGeneratedResolver] 12 | public sealed class LocalDateAsExtMessagePackFormatter : IMessagePackFormatter 13 | { 14 | public static readonly LocalDateAsExtMessagePackFormatter Instance = new LocalDateAsExtMessagePackFormatter(); 15 | 16 | // copied from Nodatime code as this details are not exposed even if they would be great for serialization 17 | internal const int CalendarBits = 6; // Up to 64 calendars. 18 | internal const int DayBits = 6; // Up to 64 days in a month. 19 | internal const int MonthBits = 5; // Up to 32 months per year. 20 | internal const int YearBits = 15; // 32K range; only need -10K to +10K. 21 | internal const int CalendarDayBits = CalendarBits + DayBits; 22 | internal const int CalendarDayMonthBits = CalendarDayBits + MonthBits; 23 | 24 | internal const int CalendarMask = (1 << CalendarBits) - 1; 25 | internal const int DayMask = ((1 << DayBits) - 1) << CalendarBits; 26 | internal const int MonthMask = ((1 << MonthBits) - 1) << CalendarDayBits; 27 | internal const int YearMask = ((1 << YearBits) - 1) << CalendarDayMonthBits; 28 | 29 | public void Serialize(ref MessagePackWriter writer, LocalDate value, MessagePackSerializerOptions options) 30 | { 31 | uint v = 0; 32 | unchecked 33 | { 34 | v = (uint)( 35 | ((value.Year - 1) << CalendarDayMonthBits) | 36 | ((value.Month - 1) << CalendarDayBits) | 37 | ((value.Day - 1) << CalendarBits) | 38 | 0 39 | ); 40 | } 41 | byte[] b = { MessagePackCode.FixExt4 42 | , unchecked((byte)NodatimeMessagePackExtensionTypeCode.LocalDate) 43 | , unchecked((byte)(v >> 24)) 44 | , unchecked((byte)(v >> 16)) 45 | , unchecked((byte)(v >> 8)) 46 | , unchecked((byte)v) 47 | }; 48 | 49 | writer.WriteRaw(b); 50 | } 51 | 52 | public LocalDate Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 53 | { 54 | var v = reader.ReadInt32(); 55 | var year = unchecked(((v & YearMask) >> CalendarDayMonthBits) + 1); 56 | var month = unchecked(((v & MonthMask) >> CalendarDayBits) + 1); 57 | var day = unchecked(((v & DayMask) >> CalendarBits) + 1); 58 | 59 | return new LocalDate(year, month, day); 60 | } 61 | } 62 | 63 | // Supported 64 | public sealed class LocalDateAsDatetimeMessagePackFormatter : IMessagePackFormatter 65 | { 66 | public static readonly LocalDateAsDatetimeMessagePackFormatter Instance = new LocalDateAsDatetimeMessagePackFormatter(); 67 | 68 | public LocalDate Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 69 | { 70 | var dt = reader.ReadDateTime(); 71 | LocalDateTime ldt = LocalDateTime.FromDateTime(dt); 72 | 73 | if (ldt.TimeOfDay != LocalTime.Midnight) 74 | throw new InvalidOperationException($"Local Date should not contain time part. Found {ldt.TimeOfDay} instead of midnight"); 75 | 76 | return LocalDate.FromDateTime(dt); 77 | } 78 | 79 | public void Serialize(ref MessagePackWriter writer, LocalDate value, MessagePackSerializerOptions options) 80 | { 81 | writer.Write(DateTime.SpecifyKind(value.ToDateTimeUnspecified(), DateTimeKind.Utc)); 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/LocalDateTimeAsDateTimeMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | using System; 7 | 8 | namespace MessagePack.NodaTime 9 | { 10 | public sealed class LocalDateTimeAsDateTimeMessagePackFormatter : IMessagePackFormatter 11 | { 12 | public static readonly LocalDateTimeAsDateTimeMessagePackFormatter Instance = new LocalDateTimeAsDateTimeMessagePackFormatter(); 13 | 14 | public LocalDateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 15 | { 16 | var dt = reader.ReadDateTime(); 17 | return LocalDateTime.FromDateTime(dt); 18 | } 19 | 20 | public void Serialize(ref MessagePackWriter writer, LocalDateTime value, MessagePackSerializerOptions options) 21 | { 22 | writer.Write(DateTime.SpecifyKind(value.ToDateTimeUnspecified(), DateTimeKind.Utc)); // cast to UTC to permit roundtrip 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/LocalTimeMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | 7 | namespace MessagePack.NodaTime 8 | { 9 | public sealed class LocalTimeAsNanosecondsMessagePackFormatter : IMessagePackFormatter 10 | { 11 | public static readonly LocalTimeAsNanosecondsMessagePackFormatter Instance = new LocalTimeAsNanosecondsMessagePackFormatter(); 12 | 13 | public LocalTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 14 | { 15 | var nanos = reader.ReadInt64(); 16 | return LocalTime.Midnight.PlusNanoseconds(nanos); 17 | } 18 | 19 | public void Serialize(ref MessagePackWriter writer, LocalTime value, MessagePackSerializerOptions options) 20 | { 21 | writer.WriteInt64(value.NanosecondOfDay); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/MessagePack.NodaTime.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Library 6 | 7 | 8 | MessagePack.NodaTime 9 | 10 | MessagePack.NodaTime 11 | This library adds support for NodaTime types to MessagePack C#. 12 | 13 | 14 | chore: update base libraries 15 | feat: add support for nullable 16 | 17 | 18 | MessagePack;MsgPack;NodaTime;Serialize;Serialization;Ark;C#;Formatter;Resolver;DateTime;Visual Studio;.NET;Framework 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/NodatimeMessagePackExtensionTypeCode.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | namespace MessagePack.NodaTime 5 | { 6 | public static class NodatimeMessagePackExtensionTypeCode 7 | { 8 | public const sbyte LocalDate = 40; 9 | public const sbyte LocalTime = 41; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/NodatimeResolver.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | using System; 7 | using System.Collections.Generic; 8 | 9 | namespace MessagePack.NodaTime 10 | { 11 | public sealed class NodatimeResolver : IFormatterResolver 12 | { 13 | // Resolver should be singleton. 14 | public static readonly IFormatterResolver Instance = new NodatimeResolver(); 15 | 16 | NodatimeResolver() 17 | { 18 | } 19 | 20 | // GetFormatter's get cost should be minimized so use type cache. 21 | public IMessagePackFormatter? GetFormatter() 22 | { 23 | return FormatterCache.Formatter; 24 | } 25 | 26 | static class FormatterCache 27 | { 28 | public static readonly IMessagePackFormatter? Formatter; 29 | 30 | // generic's static constructor should be minimized for reduce type generation size! 31 | // use outer helper method. 32 | static FormatterCache() => Formatter = (IMessagePackFormatter?)NodatimeResolverGetFormatterHelper.GetFormatter(typeof(T)); 33 | } 34 | } 35 | 36 | internal static class NodatimeResolverGetFormatterHelper 37 | { 38 | static readonly Dictionary _formatterMap = new Dictionary() 39 | { 40 | {typeof(Instant), InstantMessagePackFormatter.Instance}, 41 | {typeof(LocalDate), LocalDateAsDatetimeMessagePackFormatter.Instance}, 42 | {typeof(LocalTime), LocalTimeAsNanosecondsMessagePackFormatter.Instance}, 43 | {typeof(LocalDateTime), LocalDateTimeAsDateTimeMessagePackFormatter.Instance}, 44 | 45 | {typeof(Offset), OffsetMessagePackFormatter.Instance}, 46 | {typeof(Period), PeriodAsIntArrayMessagePackFormatter.Instance}, 47 | {typeof(Duration), DurationAsBclTicksMessagePackFormatter.Instance }, 48 | 49 | {typeof(OffsetDateTime), OffsetDateTimeMessagePackFormatter.Instance}, 50 | {typeof(ZonedDateTime), ZonedDateTimeMessagePackFormatter.Instance}, 51 | 52 | {typeof(Instant?), new NullableFormatter() }, 53 | {typeof(LocalDate?), new NullableFormatter() }, 54 | {typeof(LocalTime?), new NullableFormatter() }, 55 | {typeof(LocalDateTime?), new NullableFormatter() }, 56 | {typeof(Offset?), new NullableFormatter() }, 57 | {typeof(OffsetDateTime?), new NullableFormatter() }, 58 | {typeof(ZonedDateTime?), new NullableFormatter() }, 59 | {typeof(Duration?), new NullableFormatter() }, 60 | }; 61 | 62 | internal static object? GetFormatter(Type t) 63 | { 64 | if (_formatterMap.TryGetValue(t, out var formatter)) 65 | { 66 | return formatter; 67 | } 68 | 69 | // If type can not get, must return null for fallback mechanism. 70 | return null; 71 | } 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /MessagePack.NodaTime/OffsetDateTimeMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | using System; 7 | 8 | namespace MessagePack.NodaTime 9 | { 10 | public sealed class OffsetDateTimeMessagePackFormatter : IMessagePackFormatter 11 | { 12 | public static readonly OffsetDateTimeMessagePackFormatter Instance = new OffsetDateTimeMessagePackFormatter(); 13 | 14 | public OffsetDateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 15 | { 16 | var count = reader.ReadArrayHeader(); 17 | 18 | if (count != 2) 19 | throw new InvalidOperationException("Invalid array count"); 20 | 21 | var dt = LocalDateTimeAsDateTimeMessagePackFormatter.Instance.Deserialize(ref reader, options); 22 | var off = OffsetMessagePackFormatter.Instance.Deserialize(ref reader, options); 23 | 24 | return new OffsetDateTime(dt, off); 25 | } 26 | 27 | public void Serialize(ref MessagePackWriter writer, OffsetDateTime value, MessagePackSerializerOptions options) 28 | { 29 | var dt = value.LocalDateTime; 30 | var off = value.Offset; 31 | 32 | writer.WriteArrayHeader(2); 33 | LocalDateTimeAsDateTimeMessagePackFormatter.Instance.Serialize(ref writer, dt, options); 34 | OffsetMessagePackFormatter.Instance.Serialize(ref writer, off, options); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/OffsetMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | 7 | namespace MessagePack.NodaTime 8 | { 9 | public sealed class OffsetMessagePackFormatter : IMessagePackFormatter 10 | { 11 | public static readonly OffsetMessagePackFormatter Instance = new OffsetMessagePackFormatter(); 12 | 13 | public Offset Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 14 | { 15 | var seconds = reader.ReadInt32(); 16 | return Offset.FromSeconds(seconds); 17 | } 18 | 19 | public void Serialize(ref MessagePackWriter writer, Offset value, MessagePackSerializerOptions options) 20 | { 21 | writer.WriteInt32(value.Seconds); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /MessagePack.NodaTime/PeriodMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | 6 | using NodaTime; 7 | using NodaTime.Text; 8 | 9 | using System; 10 | 11 | namespace MessagePack.NodaTime 12 | { 13 | [ExcludeFormatterFromSourceGeneratedResolver] 14 | public sealed class PeriodAsIsoStringMessagePackFormatter : IMessagePackFormatter 15 | { 16 | public static readonly PeriodAsIsoStringMessagePackFormatter Instance = new PeriodAsIsoStringMessagePackFormatter(); 17 | 18 | public Period? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 19 | { 20 | if (reader.IsNil) 21 | { 22 | return null; 23 | } 24 | 25 | var s = reader.ReadString(); 26 | if (s == null) 27 | return null; 28 | if (s.Length == 0) 29 | return Period.Zero; 30 | 31 | return PeriodPattern.Roundtrip.Parse(s).GetValueOrThrow(); 32 | } 33 | 34 | public void Serialize(ref MessagePackWriter writer, Period? value, MessagePackSerializerOptions options) 35 | { 36 | if (value == null) 37 | { 38 | writer.WriteNil(); 39 | return; 40 | } 41 | 42 | writer.Write(PeriodPattern.Roundtrip.Format(value)); 43 | } 44 | } 45 | 46 | public sealed class PeriodAsIntArrayMessagePackFormatter : IMessagePackFormatter 47 | { 48 | public static readonly PeriodAsIntArrayMessagePackFormatter Instance = new PeriodAsIntArrayMessagePackFormatter(); 49 | 50 | public Period? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 51 | { 52 | if (reader.IsNil) 53 | { 54 | return null; 55 | } 56 | var count = reader.ReadArrayHeader(); 57 | if (count != 10) throw new InvalidOperationException("Invalid array count"); 58 | 59 | var years = reader.ReadInt32(); 60 | var months = reader.ReadInt32(); 61 | var weeks = reader.ReadInt32(); 62 | var days = reader.ReadInt32(); 63 | var hours = reader.ReadInt64(); 64 | var minutes = reader.ReadInt64(); 65 | var seconds = reader.ReadInt64(); 66 | var milliseconds = reader.ReadInt64(); 67 | var ticks = reader.ReadInt64(); 68 | var nano = reader.ReadInt64(); 69 | 70 | return new PeriodBuilder() 71 | { 72 | Years = years, 73 | Months = months, 74 | Weeks = weeks, 75 | Days = days, 76 | Hours = hours, 77 | Minutes = minutes, 78 | Seconds = seconds, 79 | Milliseconds = milliseconds, 80 | Ticks = ticks, 81 | Nanoseconds = nano, 82 | } 83 | .Build(); 84 | } 85 | 86 | public void Serialize(ref MessagePackWriter writer, Period? value, MessagePackSerializerOptions options) 87 | { 88 | if (value == null) 89 | { 90 | writer.WriteNil(); 91 | return; 92 | } 93 | 94 | writer.WriteArrayHeader(10); 95 | writer.WriteInt32(value.Years); 96 | writer.WriteInt32(value.Months); 97 | writer.WriteInt32(value.Weeks); 98 | writer.WriteInt32(value.Days); 99 | writer.WriteInt64(value.Hours); 100 | writer.WriteInt64(value.Minutes); 101 | writer.WriteInt64(value.Seconds); 102 | writer.WriteInt64(value.Milliseconds); 103 | writer.WriteInt64(value.Ticks); 104 | writer.WriteInt64(value.Nanoseconds); 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /MessagePack.NodaTime/ZonedDateTimeMessagePackFormatter.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) ARK LTD. All rights reserved. 2 | // Licensed under the MIT License. See LICENSE in the project root for 3 | // license information. 4 | using MessagePack.Formatters; 5 | using NodaTime; 6 | using System; 7 | 8 | namespace MessagePack.NodaTime 9 | { 10 | public sealed class ZonedDateTimeMessagePackFormatter : IMessagePackFormatter 11 | { 12 | public static readonly ZonedDateTimeMessagePackFormatter Instance = new ZonedDateTimeMessagePackFormatter(); 13 | 14 | public ZonedDateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options) 15 | { 16 | var count = reader.ReadArrayHeader(); 17 | if (count != 3) 18 | throw new InvalidOperationException("Invalid array count"); 19 | 20 | var dt = LocalDateTimeAsDateTimeMessagePackFormatter.Instance.Deserialize(ref reader, options); 21 | var off = OffsetMessagePackFormatter.Instance.Deserialize(ref reader, options); 22 | var zoneId = reader.ReadString(); 23 | if (zoneId == null) 24 | throw new InvalidOperationException("ZoneId, 3rd member of array, cannot be null"); 25 | 26 | return new ZonedDateTime(dt, DateTimeZoneProviders.Tzdb[zoneId], off); 27 | } 28 | 29 | public void Serialize(ref MessagePackWriter writer, ZonedDateTime value, MessagePackSerializerOptions options) 30 | { 31 | var dt = value.LocalDateTime; 32 | var off = value.Offset; 33 | var zoneId = value.Zone.Id; 34 | 35 | writer.WriteArrayHeader(3); 36 | LocalDateTimeAsDateTimeMessagePackFormatter.Instance.Serialize(ref writer, dt, options); 37 | OffsetMessagePackFormatter.Instance.Serialize(ref writer, off, options); 38 | writer.Write(zoneId); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /MessagePack.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33424.131 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessagePack.NodaTime", "MessagePack.NodaTime\MessagePack.NodaTime.csproj", "{00D42F91-2E9A-4138-B667-1DE2A971F28D}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6A7019F5-E02F-471F-9A4D-5C7D50F55BD3}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{4C82ACD9-7737-4742-A657-336B2916D383}" 11 | EndProject 12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MessagePack.NodaTime.Tests", "MessagePack.NodaTime.Tests\MessagePack.NodaTime.Tests.csproj", "{6752BA3A-6660-4B8C-9ECD-F6E03A848CB7}" 13 | EndProject 14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EF124151-0766-460F-A634-BA924ED65C5A}" 15 | ProjectSection(SolutionItems) = preProject 16 | .editorconfig = .editorconfig 17 | .gitignore = .gitignore 18 | Directory.Build.props = Directory.Build.props 19 | global.json = global.json 20 | README.md = README.md 21 | EndProjectSection 22 | EndProject 23 | Global 24 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 25 | Debug|Any CPU = Debug|Any CPU 26 | Release|Any CPU = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {00D42F91-2E9A-4138-B667-1DE2A971F28D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {00D42F91-2E9A-4138-B667-1DE2A971F28D}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {00D42F91-2E9A-4138-B667-1DE2A971F28D}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {00D42F91-2E9A-4138-B667-1DE2A971F28D}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {6752BA3A-6660-4B8C-9ECD-F6E03A848CB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {6752BA3A-6660-4B8C-9ECD-F6E03A848CB7}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {6752BA3A-6660-4B8C-9ECD-F6E03A848CB7}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {6752BA3A-6660-4B8C-9ECD-F6E03A848CB7}.Release|Any CPU.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(SolutionProperties) = preSolution 39 | HideSolutionNode = FALSE 40 | EndGlobalSection 41 | GlobalSection(NestedProjects) = preSolution 42 | {00D42F91-2E9A-4138-B667-1DE2A971F28D} = {6A7019F5-E02F-471F-9A4D-5C7D50F55BD3} 43 | {6752BA3A-6660-4B8C-9ECD-F6E03A848CB7} = {4C82ACD9-7737-4742-A657-336B2916D383} 44 | EndGlobalSection 45 | GlobalSection(ExtensibilityGlobals) = postSolution 46 | SolutionGuid = {D5C0F386-B0D0-4E1E-A00E-0629D6300818} 47 | EndGlobalSection 48 | EndGlobal 49 | -------------------------------------------------------------------------------- /MessagePack.sln.licenseheader: -------------------------------------------------------------------------------- 1 | extensions: designer.cs generated.cs 2 | extensions: .cs .cpp .h 3 | // Copyright (c) ARK LTD. All rights reserved. 4 | // Licensed under the MIT License. See LICENSE in the project root for 5 | // license information. 6 | extensions: .aspx .ascx 7 | <%-- 8 | Copyright (c) ARK LTD. All rights reserved. 9 | Licensed under the MIT License. See License.txt in the project root for 10 | license information. 11 | --%> 12 | extensions: .vb 13 | 'Copyright (c) ARK LTD. All rights reserved. 14 | Licensed under the MIT License. See License.txt in the project root for 15 | license information. 16 | extensions: .xml .config .xsd 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](./ark-dark.png) 2 | # MessagePack.NodaTime 3 | 4 | This library adds support for NodaTime types to MessagePack C#. 5 | 6 | ## Getting Started 7 | 8 | ### Installation 9 | #### Prerequisities for C# 10 | * [MessagePack](https://www.nuget.org/packages/MessagePack/) 11 | * [NodaTime](https://www.nuget.org/packages/NodaTime/) 12 | 13 | 14 | This library is provided in NuGet. 15 | 16 | Support for .NET Framework 4.5, .NET Framework 4.6.1, .NET Standard 1.6 and .NET Standard 2.0. 17 | 18 | In the Package Manager Console - 19 | ``` 20 | Install-Package MessagePack.NodaTime 21 | ``` 22 | or download directly from NuGet. 23 | ## How to use 24 | To use the NodaTime resolver, you will have to add it to the composite resolver, as shown in the example below: 25 | ```csharp 26 | CompositeResolver.RegisterAndSetAsDefault( 27 | BuiltinResolver.Instance, 28 | AttributeFormatterResolver.Instance, 29 | SourceGeneratedFormatterResolver.Instance, 30 | NodatimeResolver.Instance, 31 | DynamicEnumAsStringResolver.Instance, 32 | ContractlessStandardResolver.Instance 33 | ); 34 | ``` 35 | ## Quick Start 36 | For more information on either MessagePack or NodaTime, please follow the respective links below. 37 | * [MesssagePack](https://github.com/neuecc/MessagePack-CSharp/blob/master/README.md) 38 | * [NodaTime](https://nodatime.org/) 39 | 40 | This is a quick guide on a basic serialization and de-serialization of a NodaTime type. 41 | 42 | ```csharp 43 | Instant inst = new Instant(); 44 | var bin = MessagePackSerializer.Serialize(inst); 45 | var res = MessagePackSerializer.Deserialize(bin); 46 | // inst == res 47 | ``` 48 | 49 | ## Usage 50 | ### Supported NodaTime types 51 | `Insant`, `LocalTime`, `LocalDate`, `LocalDateTime`,`Offset`, `OffsetDateTime`, `Period` and `ZonedDateTime` 52 | 53 | ### Timestamps 54 | #### Serialization 55 | As per the MessagePack spec, when we serialize a NodaTime type of LocalDateTime, LocalDate or Instant, an extension type of -1 is received meaning it is a MessagePack timestamp. 56 | 57 | Timestamp spec can be found [here](https://github.com/msgpack/msgpack/blob/master/spec.md#timestamp-extension-type). 58 | 59 | An example of this in C# is shown below: 60 | ```csharp 61 | LocalDateTime ldt = LocalDateTime.FromDateTime(DateTime.Now); 62 | // This date is within the range for timestamp32 63 | 64 | var localDateTimeBinary = MessagePackSerializer.Serialize(ldt); 65 | // Once serialized we can expect the format to be [0xd6, -1, data] (format, extension type, data in bytes), 66 | // and ‘localDateTimeBinary’ to be a byte array of size 6 67 | ``` 68 | 69 | #### Deserialization 70 | In the same way we can support serialization from NodaTime (eg, LocalDate) to MessagePack (timestamp), the same is applied for deserialization. 71 | 72 | From a timestamp, we can deserialize into a LocalDate (if time part is 0), LocalDateTime or an Instant. 73 | 74 | From the snippet of code in serialization, shown below is deserialization: 75 | ```csharp 76 | var res = MessagePackSerializer.Deserialize(localDateTimeBinary); 77 | ``` 78 | :heavy_exclamation_mark: Deserializing a LocalDateTime into a LocalDate, will not work if the time value is not 0. 79 | 80 | ### NodaTime serialized formats 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 92 | 95 | 99 |
NodaTime typeSerialization format
InstantWhen an Instant is serialized, like LocalDateTime and LocalDate, it goes to timestamp format. Depending on the value of the Instant, it will fall into either timestamp 32, 64, or 96 format, as explained above under the Timestamp heading.
LocalDateOnce a LocalDate is serialized it is in timestamp format. Depending on the value of the LocalDate, it will fall into either timestamp 32, 64 or 96. LocalDate has no time values.
LocalDateTimeOnce a LocalDate is serialized it is in timestamp format. This means an extension type of -1 will be received by MessagePack. LocalDateTime can be deserialized into a LocalDate if it has no time part.
LocalTimeLocalTime is serialized into an int64 (64 bit int). The int64 contains the LocalTime value in nanoseconds.
OffsetOffset is serialized into an int32 (32 bit int). The int32 contains the Offset value in seconds.
OffsetDateTimeWhen an Offset is serialized, it is split up into into the LocalDateTime and Offset parts. 89 | They are then serialized using there respective formatters. 90 | This means the serialized OffsetDateTime will be put into an array of 2 elements which looks like [timestamp, int32]. 91 | The Offset and LocalDateTime serialization is explained in the headings above.
PeriodWhen the NodaTime type Period is serialized, it is split into a 'fixarray'. 93 | For a Period we have a 10 element array of four int32 amd six int64 respectively, represented in the order of → 94 | Years, Months, Weeks, Days, Hours, Minutes, Seconds, Milliseconds, Ticks, Nanoseconds.
ZonedDateTimeA ZonedDateTime is split up into LocalDateTime, an Offset and a string representing a Zone, during serialization. 96 | This means the ZonedDateTime is put into an array of 3 elements. 97 | Each NodaTime type is serialized using there respective formatters, 98 | while the string is serialized using the MessagePack base class into a 'fixstr'.
100 | 101 | ## Limitations 102 | ### Nanoseconds 103 | While NodaTime supports nanoseconds accuracy, we currently do not. The lowest common level of precision between us and NodaTime is ticks. This means our serialization and deserialization process truncates at 100 nanoseconds because 100ns = 1 tick. 104 | Below are two examples explaining this: 105 | ```csharp 106 | LocalDateTime ldt = new LocalDateTime(2016, 08, 21, 0, 0, 0, 0).PlusNanoseconds(1) 107 | 108 | var localDateTimeBinary = MessagePackSerializer.Serialize(ldt); 109 | var result MessagePackSerializer.Deserialize(localDateTimeBinary); 110 | 111 | // ldt != result, nanosecond accuracy is lost in process. 112 | ``` 113 | 114 | ```csharp 115 | LocalDateTime ldt = new LocalDateTime(2016, 08, 21, 0, 0, 0, 0).PlusNanoseconds(100); 116 | 117 | var localDateTimeBinary = MessagePackSerializer.Serialize(ldt); 118 | var result = MessagePackSerializer.Deserialize(localDateTimeBinary); 119 | 120 | // ldt == result, returns truncated value equal to 1 tick. 121 | ``` 122 | 123 | ### UTC 124 | In the base [MessagePack](https://github.com/neuecc/MessagePack-CSharp) library, DateTime values are converted to UTC before being serialized. While using our library, you must specify DateTimeKind as UTC before serializing when using DateTime and the LocalDateTime type, and expect it as UTC when deserializing. 125 | 126 | ## Interoperability 127 | As explained previously, we use the timestamp format for some of our serialized NodaTime types. The timestamp format is interoperable with [MessagePack for C#](https://github.com/neuecc/MessagePack-CSharp), the official [MsgPack library](https://github.com/msgpack/msgpack/blob/master/spec.md) and any other MessagePack implementations that support the extension type of -1. 128 | 129 | ## Contributing 130 | *TBC* 131 | 132 | ## Links 133 | * [Nuget](https://www.nuget.org/packages/MessagePack.NodaTime/) 134 | * [Github](https://github.com/ARKlab/MessagePack) 135 | * [Ark Energy](http://www.ark-energy.eu/) 136 | 137 | 138 | ## License 139 | This project is licensed under the MIT License - see the [LICENSE.md](https://github.com/ARKlab/MessagePack/blob/master/LICENSE) file for details 140 | 141 | ## Acknowledgments 142 | * [MessagePack for C#](https://github.com/neuecc/MessagePack-CSharp) 143 | * [NodaTime](https://nodatime.org/) 144 | * [MsgPack Spec](https://github.com/msgpack/msgpack/blob/master/spec.md) 145 | -------------------------------------------------------------------------------- /ark-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ARKlab/MessagePack/8d3958549c44e8074fc1c14ff96e538dcaade91c/ark-dark.png -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.410", 4 | "rollForward": "latestFeature" 5 | } 6 | } -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "local>ARKlab/renovate-config" 5 | ] 6 | } 7 | --------------------------------------------------------------------------------