We can retrieve  information about metadata hotfixes installed directly from Visual Studio using “Apply Hotfix” addin ( Dynamics 365 -> Addins -> Apply Hotfix).

ApplyHotfix_ViewInstalledHotfixes

But who wants to click that button if we can write X++ job ?    All information could be retrieved using powerful  Metadata API.

public static class ShowAllInstalledHotfixes
{
    public static void main(Args _args)
    {
        var environment = Microsoft.Dynamics.ApplicationPlatform.Environment.EnvironmentFactory::GetApplicationEnvironment();

        Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider metadataProvider = ShowAllInstalledHotfixes::getDiskMetadataProvider(environment);

        // or runtime
        // Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider metadataProvider = ShowAllInstalledHotfixes::getRuntimeMetadataProvider(environment);

        Microsoft.Dynamics.AX.Metadata.Providers.IMetaUpdateProvider updateProvider = metadataProvider.get_Updates();

        var moduleInfoList = metadataProvider.ModelManifest.ListModules();
        var i = moduleInfoList.GetEnumerator();

        setPrefix('KBs Installed');

        while (i.MoveNext())
        {
            Microsoft.Dynamics.AX.Metadata.MetaModel.IModuleInfo moduleInfo = i.get_Current();
            System.String moduleName = moduleInfo.get_Name();

            setPrefix(moduleName);

            var updatesEnumerator = updateProvider.ListObjects(moduleName).GetEnumerator();;
            while (updatesEnumerator.moveNext())
            {
                System.String axUpdateName = updatesEnumerator.get_Current();
                Microsoft.Dynamics.AX.Metadata.MetaModel.AxUpdate axUpdateObject = updateProvider.Read(axUpdateName);

                utcdatetime appliedDateTime = axUpdateObject.get_AppliedDateTime();
                setPrefix(strFmt('Name %1, Applied %2', axUpdateObject.get_Name(), appliedDateTime));
                var n = axUpdateObject.get_KBNumbers().GetEnumerator();
                while (n.MoveNext())
                {
                    info(n.get_Current());
                }
            }
        }
    }

    public static Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider getDiskMetadataProvider(Microsoft.Dynamics.ApplicationPlatform.Environment.IApplicationEnvironment _environment)
    {
        Microsoft.Dynamics.AX.Metadata.Storage.DiskProvider.DiskProviderConfiguration diskProviderConfiguration = new Microsoft.Dynamics.AX.Metadata.Storage.DiskProvider.DiskProviderConfiguration();

        diskProviderConfiguration.AddMetadataPath(_environment.get_Aos().get_PackageDirectory());

        Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory metadataProvicerFactory = new Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory();

        return metadataProvicerFactory.CreateDiskProvider(diskProviderConfiguration);
    }

    public static Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider getRunTimeMetadataProvider(Microsoft.Dynamics.ApplicationPlatform.Environment.IApplicationEnvironment _environment)
    {
        Microsoft.Dynamics.AX.Metadata.Storage.Runtime.RuntimeProviderConfiguration runtimeProviderConfiguration = new Microsoft.Dynamics.AX.Metadata.Storage.Runtime.RuntimeProviderConfiguration(_environment.get_Aos().get_PackageDirectory());

        Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory metadataProvicerFactory = new Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory();

        return metadataProvicerFactory.CreateRuntimeProvider(runtimeProviderConfiguration);
    }
}

Result

ApplyHotfix_ViewInstalledHotfixesX++

As you can see, there are two methods to create Metadata provider: one for disk and another one for runtime. Runtime provider does not return AppliedDateTime or Name, so I assume that they do not exist at runtime. Disk provider has this information but, as you know, we have source code only in dev environments.

Source code on GitHub.